认识C++和C的区别
C++最简单的程序
头文件包含问题
#include <iostream> //不需要.h 直接包含 int main() { return 0; }
- 创建的项目源文件后缀是.cpp
- 头文件的包含不同
- 不需要.h 直接包含
- C语言的标准库头文件
- 依然按照原来方式包含,一定程序C++兼容C语言
- C++包含方式: c+原来的头文件,去掉.h
#include <ctime>
- 自己的写头文件: 按照C语言教的方式包含
完整代码
#include <iostream> #include <stdio.h> #include <ctime> #include <cstdlib> #include "myhead.h" //自己写的依旧是按照原来方式 int main() { printf("C语言的函数!\n"); return 0; }
C++命名空间
什么是命名空间
可以提高标识符使用,可以避免命名污染
如何创建命名空间
namespace 空间名 { //变量 //函数 //结构体 //类 } //用namespace 声明一个东西
怎么访问命名空间
- :: 作用域分辨符
- 访问空间中的成员: 空间名::成员名
- 用来区分全局变量和局部变量
- ::全局变量
#include <iostream> #include <cstdio> namespace MM { int age = 1; void print() { printf("MM\n"); } } namespace Boy { int age = 2; } int g_num = 1001; int main() { printf("%d\n", MM::age); printf("%d\n", Boy::age); int g_num = 1; printf("全局变量:%d\n", ::g_num); return 0; }
- 省略前缀的方式去调用
//using namespace 空间名; //要省略的空间名 //注意点:有作用域 #include <iostream> #include <cstdio> namespace MM { int age = 1; void print() { printf("MM\n"); } } namespace Boy { int age = 2; } int g_num = 1001; int main() { printf("%d\n", MM::age); printf("%d\n", Boy::age); int g_num = 1; printf("全局变量:%d\n", ::g_num); MM::print(); using namespace MM; //省略前缀的调用方式 print(); using namespace Boy; //printf("%d\n", age); //二义性问题:有两个选择,不知道找谁 printf("%d\n", Boy::age); printf("%d\n", MM::age); return 0; }
命名空间嵌套
namespace A { int a=1; namespace B { int b = 1; } } void test() { //剥洋葱 A::a = 1; A::B::b = 2; using namespace A::B; b = 3; }
先声明后实现
//其他写法: 先声明后实现的一种写法 namespace Data { void print(); struct student; } //必须空间名限定 void Data::print() { } struct Data::student { int age; int num; };
标准的命名空间std
- C++所有的函数和类都是属于标准命名空间
- 不写using namespace std; 意味着所有C++标准库中的东西都需要加上std::
using namespace std; //习惯性的操作
C++函数新思想
函数重载
什么是函数重载
C++允许同名不同参数的函数存在,C语言不允许同名函数存在
不同参数的三个体现
- 数目不同
- 类型不同
- 顺序不同:前提条件是存在不同类型
#include <iostream> using namespace std; //类型不同 int Max(int a, int b) { return a > b ? a : b; } float Max(float a, float b) { return a > b ? a : b; } //顺序不同 // error C2084: 函数“int Max(int,int)”已有主体 //int Max(int b, int a) //{ // //} void print(int a, char c) { } void print(char a, int c) { } //数目不同 void print(int a, int b, int c) { } //想当然了 //double就是末尾加个d 错误的 //char就是加个c 错误的 int main() { printf("%d\n", Max(1, 2)); printf("%.1f\n", Max(1.1f, 2.2f)); //错误,C++对于类型要求比C语言严格 1L; //long 1.1f; //float 1u; //unsiged; //默认的小数是double; return 0; }
函数重载和函数返回值一点毛线关系都没有。
函数缺省
什么是函数缺省
函数缺省就是给形参赋初始值,当不传参的时候使用的是默认值
函数缺省规则
- 只能从右往左缺省,中间不能有空着的
- 多文件中,.h文件缺省了,cpp不需要缺省(声明做了缺省,实现就不需要缺省)
缺省的好处
实现函数的不同形态的调用,针对不同需求做不同实现
//loadimage
//putimage
#include <iostream> using namespace std; //函数缺省 void printData(int a=1, float b = 1.11f, double c=1.11 , char d = 'A') { printf("%d\t%f\t%lf\t%c\n", a, b, c, d); } int main() { printData(); //所有形参都是默认值 printData(9); //a=9,其他值用默认值 printData(9, 2.22f); //a=9 b=2.22 其他默认值 printData(9, 2.22f, 9.9); //a=9,b=2.22 c=9.9 其他默认值 printData(9, 2.22f, 9.9,'D'); //所有的值用的是传入的值 return 0; }
C++标准输入和输出
注意点: 目前大家学会即可,不需要问为什么!!!!!后续在IO流会详细讲这些
标准输出
- cout + << 一起完成的
- 换行: endl替换"\n"
#include <iostream> using namespace std; //缺省std前缀的 struct MM { char name[20]; int age; int num; }; int main() { //单个数据输出 //没有写using namespace std; 必须加前缀 std::cout << "ILoveyou"; cout << 1; //多个数据的输出 cout << "\n"; cout << "姓名\t" << "年龄\t" << "编号\n"; struct MM mm = { "mm",18,1001 }; cout << mm.name << "\t" << mm.age << "\t" << mm.num << "\n"; //和上面一行代码效果一样 cout << mm.name << "\t"; cout << mm.age << "\t"; cout << mm.num << "\n"; cout << endl; //等效:cout<<"\n"; //一样的是std命名空间中的 std::cout << std::endl; return 0; }
标准输入
- cin + >> 一起完成
- 输入不需要任何的格式控制字符
#include <iostream> using namespace std; //缺省std前缀的 struct MM { char name[20]; int age; int num; }; int main() { cout << "请输入一个整数:"; int num; cin >> num; //变量名 cout << num << endl; cout << "请输入一个字符串:"; char str[20]; while (getchar() != '\n'); //存在跳过显现:清空缓冲区 //setbuf(stdin, NULL); //影响汉字输入,汉字的文件操作出现问题 //fflush(stdin); //C++中已经淘汰了,有时候使用没有效果 cin >> str; //数组名 cout << str << endl; cout << "input num and str:"; cin >> num >> str; cout << num << "\t" << str << endl; cout << "input name,age,num:"; struct MM temp; cin >> temp.name >> temp.age >> temp.num; cout << "姓名\t年龄\t编号" << endl; cout << temp.name << "\t" << temp.age << "\t" << temp.num << endl; return 0; }
新基本数据类型
bool类型
- 占用内存是1个字节
- 打印出来的值是: 0或者1 非零值表示成立
- 通常用的是false和true做初始化
#include <iostream> void testBool() { bool bNum = 5; std::cout << bNum << std::endl; //一般是会用都用关键字初始化 bNum = false; bNum = true; //用途: //做开关 //做标记-->查找类的操作 //做函数返回值 while (true); //死循环 } int main() { testBool(); return 0; }
引用类型
希望同学把引用类型理解为一个起别名的用法
- 左值引用
- 当做函数参数: 直接修改实参,防止拷贝本产生
- 当做返回值: 增加左值使用
- const属性限定问题
- 右值引用
- 给右值起别名
- 当做函数参数: 函数只能传入右值
- 想要传入左值,使用move函数移动
#include <iostream> using namespace std; //No.2 引用类型 void Modify(int& x) //int& x=b; { x = 9999; } //返回引用等效返回一个变量 //warning C4172: 返回局部变量或临时变量的地址: a int g_num = 1001; int& getValue() { return g_num; } int getData() { return g_num; } void printString(const char* str) //char* str="Iloveyou" { cout << str << endl; } void modifyNum(const int& num) { //num++; //常引用不能做++ cout << num << endl; } void modifyNum2(int&& num) //只能传入右值 { num++; //提供修改接口 cout << num << endl; } void testNew() { int a = 1; int& b = a; b = 1001; cout << a << endl; //当做函数返回值:增加左值使用好处 //当做函数参数:防止拷贝本的产生 Modify(b); cout << a << endl; //getData() = 1003; 错误,返回是一个值,不是一个变量,不能充当运算符左值 getValue() = 9999; //g_num=9999; cout << g_num << endl; //常量起别名 //C++对于const属性要求更为严格 //1.用常引用 const int& xx = 13; cout << xx << endl; //error C2440: “初始化”: 无法从“const char [9]”转换为“char *” const char* pstr = "ILoveyou"; printString("ILoveyou"); char array[10] = "LLLL"; printString(array); //常引用不能修改 //2.右值引用 && --->提供修改接口 int&& yy = 134; yy = 55; const int c_num = 112; //常属性的变量,依旧是左值 //int&& zz = c_num; //错误 modifyNum(1); modifyNum2(23); //左值变成右值 int data = 1001; int&& data2 = move(data); //移动函数:把左值变成右值 int value = 1234; //modifyNum2(value); //错误,用右值引用当做函数参数,不能传左值 modifyNum2(move(value)); //移动语义(完美转发) } int main() { testNew(); return 0; }
C++结构体类型
- 类型名不在需要struct关键字了
- C++结构体可以给成员直接赋初始值
- C++结构体可以包含函数
- 其实C++结构体的处理就是按照类的方式处理(后续在意)
- 用了构造函数时候C++结构体和C语言结构体处理方案是完全不同的
#include <iostream> using namespace std; //描述的是事物特征和行为 struct MM { char name[20]="MM"; int age=111; int num=1001; void initData(const char* str, int age, int num); //在结构体声明 void printData() { cout << name << "\t" << age << "\t" << num << endl; } }; //在外面实现,必须结构体名限定 void MM::initData(const char* str,int age,int num) { strcpy_s(name,20, str); //同名问题 MM::age = age; MM::num = num; } int main() { //No.1 类型不需要struct MM mm; //cout << mm.name << "\t" << mm.age << "\t" << mm.num << endl; mm.printData(); MM mm2 = { "mm2",18,1030 }; //cout << mm2.name << "\t" << mm2.age << "\t" << mm2.num << endl; mm2.printData(); mm2.initData("小芳", 18, 1004); mm2.printData(); return 0; }
C++枚举类型
#include <iostream> using namespace std; enum State {Open,Close}; enum class Color { Red, Blue }; void print(int state) { cout << state << endl; } void printEnum(Color color) { //cout << color << endl; 不能直接打印 } void testEnum() { print(1); print(Open); //C++的枚举类型不能当做一个简单的int类型 //print(Color::Red); //访问必须要用枚举类型名限定 printEnum(Color::Red); } int main() { testEnum() return 0; }
C++string类型
C++string本身是一个类,所以大家本节课只要学会使用即可,不需要问问什么
- 头文件: #include
- 注意点和cstring区别,这个是C语言头文件
- 没有用using namespace std ; string类型需要改为std::string
- 掌握string常用方式
- 创建方式
- 基本操作(比较,连接)
- 转C语言char*
微软帮助文档:basic_string 类 | Microsoft Docs
#include <iostream> #include <string> using namespace std; int main() { //std::string str; //No.1创建 string str1; str1 = "ILoveyoudsfasdfasdfasdfasdfasd"; cout << str1 << endl; string str2 = "ILoveyousdfsdafads"; cout << str2 << endl; string str3(str2); string str4 = str2; cout << str3 << endl; cout << str4 << endl; //No.2 基本操作 cout << (str3 == str4) << endl; cout << (str3 >= str4) << endl; string password; cin >> password; cout << password; //原理是:运算符重载 后面会讲 //比较直接比 if (password == string("12345")) { cout << endl << "密码正确" << endl; } int a = (int)1.3; //C语言强制类型转换 int b = int(1.34); //C++强制类型转换 //连接直接加法 string name = "张三"; string info = name + "很帅"; cout << info << endl; //上述复杂的用法 cout << info.compare(name) << endl; //和strcmp 返回值一样 cout << info.append(name) << endl; //下标的方式访问 cout << info.length() << endl; //当前长度 cout << info.size() << endl; for (int i = 0; i < info.length(); i++) { cout << info[i]; } cout << endl; for (int i = 0; i < info.length(); i++) { cout << info.at(i); } cout << endl; cout << info.capacity() << endl; //容量 //和C语言string.h有区别的 char* // 不能用%s的方式打印 //printf("%s\n", info); // 图形库中传char* 函数 都不能直接用string类型 //提供两个函数: c_str() data(); printf("%s\n", info.c_str()); printf("%s\n", info.data()); return 0; }
C++自动推断类型
- auto类型
- decltype类型
#include <iostream> using namespace std; struct MM { int age; }; MM g_MM = { 12 }; MM* createMM() { MM* p=&g_MM; return p; } int Max(int a, int b) { return a > b ? a : b; } void print(int(*Max)(int, int), int a, int b) { cout << Max(a, b) << endl; } void printData(int(*)(int, int), int, int) { cout << "另一个函数" << endl; } int main() { //auto 类型自动推断: 一定要有赋值 所以不能单独定义变量 //auto a; 没有赋值 推断不出来 auto a = 1; //int a = 134; auto pMM = createMM(); cout << pMM->age << endl; auto pFunc = print; //void (*)(int(*)(int, int), int , int ) pFunc(Max, 1, 3); pFunc = printData; pFunc(Max, 1, 3); int* p = nullptr; //新的空 等效C语言NULL //decltype 不需要赋值 decltype(123) num = 123; //decltype(123) 表示一个int类型 //函数指针必须取地址 decltype(&print) ppFunc; ppFunc = printData; //推断一个int decltype(num) Num = num; decltype(&num) pNum = # //当你们用的时候,不知道类型,推断定义变量去赋值 return 0; }
C++动态内存申请
C申请的内存是自由存储区的,C语言的堆区内存,所以C类的对象内存不能用malloc申请
// IMAGE *
- new申请内存
- 申请单个变量内存
- 申请一段内存
- 申请内存可以手动初始化
- 申请内存后可以再分配
- delete释放内存
- 释放单个变量内存:delete 指针名;
- 释放一段变量内存: delete[] 指针名;
#include <iostream> using namespace std; struct MM { char name[20]; int age; int num; }; void testOne() { int* pInt = new int; *pInt = 123; cout << pInt[0] << endl; delete pInt; pInt = nullptr; char* pc = new char; delete pc; int* pNum = new int(1234); //申请并且初始化 cout << pNum[0] << endl; delete pNum; MM* pMM = new MM({ "name",12,1101 }); cout << pMM->name << "\t" << pMM->age << "\t" << pMM->num << endl; } void testTwo() { //一段内存的申请 int size = 4; int* pArray = new int[size]; //int pArray[4]; MM* pMM = new MM[4]; //MM pMM[4]; delete[] pArray; delete[] pMM; pArray = nullptr; pMM = nullptr; int* pNum = new int[4]{ 1, 2, 3, 4 }; for (int i = 0; i < 4; i++) { cout << pNum[i] << "\t"; } cout << endl; delete[] pNum; pNum = nullptr; } void testThree() { char* pMem = new char[1024]; //在原来上面拿个20字节存整数 int* pInt = new(pMem + 0) int[5]{ 1,2,3,4,5 }; //在原来上面拿出20个存字符 char* pChar = new(pMem + 20) char[20]{"ILoveyou"}; //等效:char* pChar = new(pInt + 5) char[20]{"ILoveyou"}; delete[] pMem; pMem = nullptr; } int main() { testOne(); testTwo(); testThree(); return 0; }