1、运算符重载
(1)让对象也能通过运算符进行运算。
(2)对已有的运算符赋予更多的含义,使得同一个运算符作用域不同类型的数据时导致
不同类型的行为。
(3) 同一个运算符,对不同类型的操作数,发生不同的行为。
(4)实质是函数重载,可以重载为普通函数,也可以重载为成员函数
(5)把含有运算符的表达式转换成对运算符函数的调用
(6)运算符可以被多次重载,根据实参类型决定调用哪个运算符函数
返回值类型 operator运算符 (形参表){.........}
上面的运算符是+,-等
(7)重载为成员函数时,参数个数为运算符目数减一
重载为普通函数时,参数个数为运算符目数
2、赋值运算符的重载
(1)赋值运算符“=”只能重载为成员函数
3、运算符重载为友元函数
4、可变长数组类的实现
要用动态分配的内存来存放数组元素,需要一个指针成员变量
5、流插入运算符和流提取运算符的重载
cout是ostream类的对象
“<<”在ostream中进行了重载
6、类型转换运算符重载
类型转换运算符函数的返回值类型就是该类型,其函数返回值前面是不写出来的
其作用是把对象转换成所规定的的类型的东西
7、自增自减运算符的重载
自增自减运算符是有前置和后置之分的,为了区分,C++规定:
(1)前置运算符作为一元运算符重载
重载为成员函数:T& operator++()
重载为全局函数:T1 &operator++(T2)
(2)后置运算符作为二元运算符重载,多写一个没用的参数
重载为成员函数:T operator++(int)
重载为全局函数:T1 operator++(T2,int)
(3) 前置的返回值是一个引用,后置的返回值是一个对象
前置的执行效率高于后置
8、C++不允许重载新的运算符
重载不能改变运算符的优先级
有的运算符不能被重载:“.”,“.*”,"::","?:",sizeof
重载以下运算符的时候,运算符重载函数必须声明为类的成员函数
()、[]、---->、=
9、继承和派生
(1)继承:在定义一个新的类B时,如果该类与某个已有的类A相似
(指的是B拥有A的全部特点),那么久可以把A作为一个基类,而把B作
为基类的一个派生类。
(2)派生类是通过对基类进行扩充和修改得到的。在派生类中,可以
扩充新的成员变量和成员函数。
(3)派生类一经定以后,可以独立使用,不依赖于基类。
(4)派生类拥有基类的全部成员函数和成员变量
(5)在派生类的各成员函数中,不能访问基类的private成员
(6)写法:
class 派生类名:public 基类名{ };
(7)派生类对象的存储空间:派生类对象的体积,等于基类对象的体积,再加
上派生类对象自己的成员变量的体积。在派生类对象中,包含着基类对象,而且基类对象的存储位
置位于派生类对象新增成员变量之前。
10、继承关系和复合关系
类与类之间有三种关系:没关系、继承关系、复合关系
(1)继承关系:“是”关系
B是基类A的派生类
‘“一个B对象也是一个A对象”
(2)复合关系:“有”关系
类C中“有”成员变量K,K是类D的对象,则C和D是复合关系
“D对象是C对象的固有属性或组成部分”
11、派生类覆盖基类成员
派生类中可以定义一个和基类成员同名的成员,这叫覆盖。
在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问
由基类定义的同名成员时,要使用作用域符号::。
12、类的保护成员
(1) 基类的protected成员,可以被以下函数访问:
基类的成员函数
基类的友元函数
派生类的成员函数可以访问当前对象的基类的保护成员
(2)基类的private成员,可以被以下函数访问:
基类的成员函数
基类的友元函数
(3) 基类的public成员,可以被以下函数访问:
基类的成员函数
基类的友元函数
派生类的成员函数
派生类的友元函数
其他函数
13、派生类的构造函数
派生类列表中用基类的构造函数初始化
在创建派生类的对象时,需要嗲用基类的构造函数:初始化派生类对象中从基类
继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。
调用基类构造函数的两种方式:
(1) 显示方式:在派生类的构造函数中,为积累的构造函数提高参数
(2)隐式方式:在派生类的构造函数中,省略基类构造函数时,派生类的构造函数则
自动调用基类默认的构造函数。
14、包含成员对象的派生类的构造函数写法
初始化列表
在创建派生类的对象时:
先执行基类的构造函数,用以初始化派生类对象中从基类继承的成员
再执行各个成员对象的构造函数,用以初始化派生类对象中的成员对象
最后再执行派生类自己的构造函数
先构造的后消亡
15、public继承的赋值兼容规则(公有派生)
(1)派生类对象可以赋值给基类对象 b=d
(2)派生类对象可以初始化基类的引用 base &br = d
(3)派生类对象的地址可以赋值给基类的指针 base *p = &d
16、直接基类、间接基类
类A派生类B,类B派生类C,类C派生类D
(1)直接基类
类A是类B的直接基类,类B是类C的直接基类,类C是类D的直接基类
(2)间接基类
类A是类C的间接基类,类A是类D的间接基类,类B是类D的间接基类
(3)在声明派生类时,只要列出它的直接基类
**派生类沿着类的层次自动向上继承它的间接基类
**派生类的成员:派生类自己定义的成员,直接基类中的所有成员
所有间接基类的全部成员
17、虚函数和多态
(1)虚函数
在类的定义中,前面有virtual关键字的成员函数就是虚函数
*virtual关键字只用在类定义里的函数声明中,写函数体的时候不用
*构造函数和析构函数不能是虚函数
*虚函数可以参与多态,而普通的函数不能
(2)多态的表现形式一:
*派生类的指针可以赋值给基类的指针
*通过基类指针调用基类和派生类中的同名虚函数时:
**若该指针指向一个基类的对象,那么被调用的是基类的虚函数
**若该指针指向一个派生类的对象,那么被调用的是派生类的虚函数
这种机制叫做多态
(3)多态的表现形式二:
*派生类的对象可以赋值给基类的引用
*通过基类引用调用基类和派生类中的同名虚函数时:
**若该引用引用的是一个基类的对象,那么被调用的是基类的虚函数
**若该引用引用的是一个派生类的对象,那么被调用的是派生类的虚函数
这种机制叫做多态
18、多态的实现原理
多态 关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的
是基类还是派生类的虚函数,运行时才能确定----------这叫做动态联编
(1)多态实现的关键------虚函数表
每一个虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的
任何对象中都放着虚函数表的指针。虚函数表中列出了该类的虚函数地址,多出来的4个
字节就是用来放虚函数表的地址的。
19、虚析构函数
通过基类的指针删除派生类的对象时,通常情况下只调用基类的析构函数。
*但是,删除一个派生类的对象时,应该先调用派生类的析构函数,然后调
用基类的析构函数。
*解决办法:把基类的析构函数声明为virtual
**派生类的析构函数可以不加virtual进行声明,但他也是虚的
**通过基类的指针删除派生类的对象时,首先调用派生类的析构函数,然后调用
基类的析构函数。
*一般来说,一个类如果定义了虚函数,则应该将析构函数也定义成虚函数,
或者,一个类打算作为基类使用,应该将析构函数定义为虚函数。
*不允许以虚函数作为构造函数
20、纯虚函数和抽象类
(1)纯虚函数
没有函数体(没有花括号)的虚函数
virtual void print() =0;
(2)抽象类 包含纯虚函数的类
*抽象类只能作为基类来派生新类使用,不能创建抽象类的对象
*抽象类的指针和引用可以指向由抽象类派生出来的类的对象
A a;//错,抽象类不能创建对象
A *pa;//ok,可以定义抽象类的指针和引用
pa=new A;//错,抽象类不能创建对象
(3)在抽象类的成员函数内可以调用纯虚函数,但是在构造函数和析构函数
内部不能调用纯虚函数。
(4)如果一个类从抽象类派生而来,那么当且仅当它实现了基类中的所有纯虚函数
它才能成为非抽象类。
21、输入和输出相关的类
ios
istream ostream
ifstream iostream ofstream
fstream
(1)istream 是用于输入的流类,cin就是该类的对象
(2)ostream 是用于输出的流类,cout就是该类的对象
(3) ifstream 是用于从文件读取数据的类
(4) ofstream 是用于向文件写入数据的类
(5)iostream是既能用于输入,又能用于输出的类
(6)fstream是既能从文件中读数据, 向文件写入数据的类
22、标准流对象
22、输出/输入重定向
fropean("text1.txt","r",stdin)
fropean("text2.txt","w",stdout)
23、判断输入流结束
23、流操纵算子(控制输入输出格式)
p34先跳过
24、文件读写
可以将顺序文件看做一个有限字符构成的顺序字符流,然后像cin,cout一样读写。
p35、p36
25、函数模板
26、类模板
类型参数至少写一个
编译器由模板生成函数的过程叫做模板的实例化
不通过参数实例化函数模板
24、类模板
编译器由类模板生成类的过程叫做类模板的实例化,由类模板实例化得到的类,叫做模板类
同一个类模板的两个模板类是不兼容的
25、类模板和派生
26、String类
27、标准模板库STL