2.11作业
C++
cout
cout 是输出类的类对象,具有输出功能,可以自动识别数据类型,无需加格式符
<< 插入符(输出符)
endl 换行
cin
cin 是输入类的类对象,功能是输入,它可以自动识别数据类型,无需加格式符 无需加&
>> 提取符(输入符
C++中字符串类型string
string str5(str1, 3); //从str1下标为3的位置开始赋值
char *p = (char *)"hello"; //需要将字符串强制转换成char * 赋值给字符指针
字符串中常用的函数
size() :元素个数
empty() :判断字符串是否为空 如果为空 返回true 否则为false
capacity() :计算容量大小
字符串的元素访问
1> 下标 ------>不判断是否越界
2> at() -------->判断是否越界
字符串的输入
string userName;
cout << "请输入你的账号:" << endl;
cin >> userName; //以空格作为结束
getline(cin, userName); //可以有空格
C++数组 array
如果用array数组,需要包含头文件 #include
array<int, 5> a; // == int a[5]
array<int, 5>::iterator iter; //迭代器 == 指针, a.begin() 容器第一个元素的地址
//a.end() 容器最后一个元素的下一个元素的地址
for(iter = a.begin(); iter != a.end(); iter++)
{ cin >> *iter; }
array< array<int ,2>, 3> a; // int a[3][2]
array< array<int ,2>, 3>::iterator iter1; //迭代器 遍历每个一维数组
array<int, 2>::iterator iter2; //迭代器 遍历每个一维数组里的每个元素
for(iter1 = a.begin(); iter1 != a.end(); iter1++)
{
for(iter2 = (*iter1).begin(); iter2 != (*iter1).end(); iter2++)
{ cin >> *iter2; }
}
引用
数据类型 &引用名 = 同类型的变量名 (&引用符号)
当结构体中有引用成员的话,使用该结构体类型定义变量时,就必须定义的同时初始化,否则报错。
当引用作为函数的返回值时
1> 要求返回的变量的生命周期长
2> 静态局部变量或者时malloc申请的堆区空间
const
常变量,表示该变量的值不能修改。
C++中的类是由C++中结构体演变而来,只是默认访问权限和默认继承方式以及关键字不同。
类的关键字:class
默认访问权限是:private 私有的
默认继承方式:private 私有的
C++中动态内存分配和回收(堆区)
构造函数
功能
在类实例化对象时,会自动调用构造函数来给类对象进行申请空间和初始化使用的
类名(形参列表) { 函数体内容 }
调用时机
实例化对象时,就会自动调用构造函数。
1> 栈区
何时实例化对象,何时自动调用构造函数
2> 堆区
何时使用new,何时自动调用构造函数
初始化列表
构造函数的本身工作是完成给类对象申请空间的,而初始化工作是由初始化列表完成的。
初始化列表格式:
初始化列表是由构造函数的形参后的小括号由冒号引出。
必须使用初始化列表的情况:
1> 当类中有引用成员时,对该引用成员变量的初始化工作必须使用初始化列表
2> 当类中有常成员变量时,对该成员变量的初始化工作必须使用初始化列表
3> 当类中嵌套另一类的类对象(子对象)时,对该子对象的成员初始化工作必须使用初始化列表
结论:
当类中有嵌套另一个类对象,调用构造函数的顺序:
1> 先调用成员的构造函数,再调用自己的构造函数。
注意:只有构造函数才有初始化列表,其他函数没有
析构函数
功能
当类对象生命周期结束后,会自动调用析构函数,来给类对象回收资源(释放空间)
调用时机
当类对象生命周期结束后,会自动调用析构函数
1> 栈区
当类对象所在的函数结束时,会自动调用析构函数,释放类对象空间
2> 堆区
何时使用delete,何时自动调用析构函数
拷贝构造函数
功能
拷贝构造函数是一种特殊的构造函数,使用一个类对象给另一个类对像进行初始化的。
调用时机
1> 用一个类对象给另一个类对象初始化时,自动调用拷贝构造函数。
2> 当类对象作为函数的形参时,实参传递给形参时,自动调用拷贝构造函数。
3> 当函数返回一个类对象时,自动调用拷贝构造函数。
友元
作用
可以让一些函数或者一些类去访问另一个类的私有数据成员。
常成员函数和常对象(const)
类中所有的成员函数都可以对数据成员做修改操作,如果设计一个函数不能对数据成员修改,则需要用常成员函数完成。
类中同名的常成员函数和非常成员函数不是重复定义,而是重载关系,原因:this指针类型不同
常对象
常对象:表示该对象里的所有数据成员不能被修改
格式: const 类名 对象名;
非常对象可以调用常成员函数和非常成员函数,优先调用非常成员函数。
常对象只能调用常成员函数,如果没有常成员函数,则报错。
mutable关键字
mutable修饰成员变量,表示该成员变量可以在常成员函数中被修改(取消常属性)
运算符重载
运算符重载就是对运算符重新定义,赋予另一种功能,以适应不同的数据类型。
每个运算符都两种实现方式:
1> 成员函数实现
2> 全局函数实现
静态成员
静态数据成员和静态成员函数是属于类的,不属于类的实例,它们在所有类的实例中都是共享的。
在数据成员前加 static ----->静态数据成员
在成员函数前加 static ------>静态成员函数
静态数据成员必须在类外初始化,如果不初始化(不建议),默认为0。
静态成员函数只能访问静态数据成员,不能访问非静态数据成员。
继承
类的三大属性:封装、继承、 多态
目的
实现代码重用性(复用性)
建立父类和子类之间的联系
多态的实现,通过继承,可以实现子类对父类的重写。
保持已有类的特性,在原来的基础上,增加新的特性而构造出新类的过程,称为继承/派生。
虚继承
使汇聚子类只得到一份中间子类从公共基类继承下来的数据成员。
在中间子类的继承方式前加 virtual
虚继承后,只保留一份中间子类从公共基类继承下来的数据成员,但是不知道具体保留哪个中间子类的,所以编译器就会自动调用公共基类的无参构造函数,如果想给公共基类的数据成员初始化,则需要在汇聚子类中手动调用公共基类的有参构造函数完成初始化操作。
多态中,实现函数重写的原理
1> 类中有虚函数时,虚函数就会有一个虚指针
2> 虚指针在类的最前面,指向了虚函数表,虚函数表记录了虚函数
3> 虚指针和虚函数表是实现多态的重要机制
虚析构函数
因为父类指针指向子类对象,只作用于子类从父类继承下来的那片空间,释放父类指针,只会把父类指针指向的那片空间释放掉,子类自己拓展的空间没有得到释放,从而造成内存泄漏。
作用:
虚析构函数可以正确引导子类释放自己的空间。
1> 父类指针释放时,不仅将父类作用的那块空间释放,也会将子类拓展的空间一起释放。
2> 将父类的析构函数设置成虚析构函数,即在父类的析构函数前加virtual
纯虚函数
当父类中的虚函数只用来被子类重写的,并且没有实现的意义,那么将该函数设置成纯虚函数。
抽象类
概念:
抽象类不能实例化具体一个对象,一般用来被继承的。如果一个类中至少有一个纯虚函数,那么该类是抽象类。
如果父类是抽象类,子类继承父类后,没有对父类中纯虚函数重写,那么子类也是抽象类,也并不能实例化一个对象。
模板
1> 模板就是建立一个通用的模具 ,大大提高代码的复用性
2> C++另一个编程思想 泛型编程 主要利用的技术 模板
3> C++提供了两个主要的模板机制: 函数模板 和 类模板
函数模板
建立一个通用的函数,其函数的返回值类型或者形参类型不具体制定,用一个虚拟类型来代替。
类模板
建立一个通用的类,其类的数据成员的类型不具体制定,用一个虚拟类型来代替
auto
auto修饰变量,可以自动推导出变量的数据类型
1> auto修饰变量时,必须初始化
2> auto的右值,可以是右值,可以是表达式,也可以是函数的返回值
3> auto 不能修饰函数的形参变量
4> auto 不能修饰数组
5> auto 不能修饰非静态数据成员
lambda表达式
需要一个匿名的,临时的,可以捕获外界变量的函数时,可以用lambda表达式完成。
[](){} //lambda表达式 [捕获外界变量的方式](形参列表)->return type{函数体内容}
C++标准模板库(STL)
C++中的标准模板库(Standard Template Library),STL是C++中标准库之一。
标准模板库中使用了大量的函数模板和类模板,用来对数据结构和算法的处理。
使用类模板 要表明依赖模板的参数类型
vector容器
vector就是数组,也称为单端数组,和普通数组有区别,普通数组是静态空间,而vector空间是动态拓展的。
动态拓展:不是在原来的空间上续接新的空间,而是重新申请空间,将原来的空间里的内容,复制到刚刚申请的空间中。
vector的构造函数
函数原型:
vector< T > v; //无参构造
vector(const vector &v); //拷贝构造函数
vector(v.begin(), v.end()) ; //把区间[v.begin(), v.end())的数据拷贝给对象本身
vector(n, elem); //将n个elem拷贝给对象本身
vector赋值函数
函数原型:
vector &operator=(const vector &v); //拷贝赋值函数
assgin(v.begin(),v.end()); //将区间[v.begin(),v.end())的数据赋值给对象本身
assgin(n, elem) ;//将n个elem赋值给对象本身
智能指针