- 在类体内不允许对成员函数进行初始化。
- 定义类时,类的数据成员不占内存空间;但是,建立类的对象时,只为每个对象分配用于保存数据成员的内存,不为函数成员分配内存。
- 在定义类时,不能定义该类的变量,只能定义该类类型的指针成员和该类类型的引用成员。
- 浅拷贝和深拷贝的区别:当类的数据成员是指针类型时,深拷贝能为新的对象分配内存空间(分配内存空间一般由new运算符实现;拷贝构造函数就是深拷贝),而浅拷贝不能。
- 对象指针只能访问该类的公有数据成员和函数成员。
- 除非是作为函数参数与函数返回值,对象引用在定义时必须要初始化。
- 非静态函数有一个指向当前对象的this指针,而静态函数没有。静态函数不属于任何类。
- 在组合类的构造函数中,初始化列表既不能决定是否调用成员对象的构造函数,也不能决定调用构造函数的顺序,成员对象调用顺序由成员对象定义的顺序决定。
- 静态变量和静态对象都只被构造一次。
- 类的静态数据成员必须进行初始化,且其初始化语句既不属于任何类,也不属于包括主函数在内的任何函数。
- 静态变量的初值缺省时为0,;动态变量的缺省初值不确定。
- 静态成员函数可以直接访问类中说明的静态成员,但不能直接访问类中的非静态成员。
- 静态数据成员不是对象成员,在引用时不需要用对象名。(?为什么?)
- 不允许常对象调用任何类的成员函数,而且常对象一旦被定义,在其生存期内不允许改变。
- 只有类的常成员函数才能访问该类的常对象;const对象不能访问非常成员函数。
- 常成员函数必须进行初始化,且初始化只能通过构造函数的初始化列表进行。
- 常成员函数的定义格式:
- 常成员函数不能更新类的数据成员。
- 保护成员具有双重角色,对派生类的成员函数而言,它是共有成员,但对所在类之外定义的其它函数而言则是私有成员。
- 使用this指针返回对象则不需要调用构造函数,但会调用拷贝构造函数。
- 先建立全局变量,在建立局部变量。
构造函数的调用条件: - 建立对象时;
- 建立动态对象(如p=new char)时;
※定义对象指针、对象引用时均没有建立对象,所以此时不调用构造函数。
※数组元素为n,定义数组时调用构造函数的次数为n。
※一个对象可以建立多个构造函数,但是只有一个析构函数。
※构造函数没有返回值,也不能用void修饰。
※构造函数被声明定义为公有函数。
拷贝构造函数的调用条件: - 当用类的一个对象去初始化该类的另一个对象时;
- 如果函数的形参是类的对象,调用函数时,将对象作为函数实参传递给函数的形参;
- 如果函数的返回值是类的对象,函数执行完成,将返回值返回。
- 使用this指针返回对象。
※拷贝构造函数只能有一个参数,并且是对某个对象的引用。
※建立对象时,构造函数和拷贝构造函数有且仅有一个被调用。
※再重新定义拷贝构造函数后,默认拷贝构造函数与默认构造函数就不存在了;但是,再重新定义构造函数后,默认构造函数就不存在了,但默认拷贝构造函数还存在。
析构函数的调用条件:析构函数在程序结束时由系统自动调用。
组合对象的构造函数的调用顺序:在定义一个组合类的对象时,不仅他自身的构造函数将被调用,而且还将调用其成员函数的构造函数,调用先后顺序为: - 成员对象按照在其组合类的声明中出现的次序,依次调用各自的构造函数,而不是按初始化列表中的顺序。
- 组合类对象调用组合类构造函数。
- 调用析构函数,析构函数的调用顺序与构造函数正好相反。
构造、拷贝以及析构函数的调用顺序:对象被析构的顺序与其创建的顺序相反。
构造函数不能声明为虚函数,析构函数可以声明为虚函数,而且有时是必须声明为虚函数。
不建议在构造函数和析构函数里面调用虚函数。
构造函数不能声明为虚函数的原因是:
1 构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的。而在构造一个对象时,由于对象还未构造成功。编译器无法知道对象 的实际类型,是该类本身,还是该类的一个派生类,或是更深层次的派生类。无法确定。。。
2 虚函数的执行依赖于虚函数表。而虚函数表在构造函数中进行初始化工作,即初始化vptr,让他指向正确的虚函数表。而在构造对象期间,虚函数表还没有被初 始化,将无法进行。
虚函数的意思就是开启动态绑定,程序会根据对象的动态类型来选择要调用的方法。然而在构造函数运行的时候,这个对象的动态类型还不完整,没有办法确定它到底是什么类型,故构造函数不能动态绑定。(动态绑定是根据对象的动态类型而不是函数名,在调用构造函数之前,这个对象根本就不存在,它怎么动态绑定?)
1.如果几类定义了带形参表的构造函数时,派生类就应当定义构造函数。如果积累没有定义构造函数,派生类也可以不定义构造函数。
2、派生类的构造函数和析构函数都不能被继承。
3、多继承时,对同一个基类,不允许直接继承两次。
4、最远派生类(c++将建立对象时所使用的派生类称为最远派生类)的构造函数要调用该公共基类的构造函数,而且只能被调用一次。
5、公共虚基类子对象只初始化一次。
6、c++规定,在初始化列表中同时出现对虚基类和非虚基类构造函数的调用,虚基类的构造函数优于非虚基类的构造函数的执行。
类型兼容的三种情况:
1、派生类对象可以赋值给基类对象;
2、派生类对象可以初始化积累的引用;
3、派生类的地址可以赋值给指向基类的指针。
单继承或多继承时,派生类构造函数的调用顺序:
1、调用基类的构造函数;
2、调用内嵌成员对象的构造函数调用顺序按照它们在类中定义的顺序;
3、派生类自己的构造函数。
单继承时,派生类的析构构造函数的调用顺序:
1、调用派生类析构函数;
2、然后调用派生类成员对象析构函数;
3、最后调用基类析构函数。
1、c++中的运算符除了“1.2.* 3::4?:5 siziof”之外,其余全部可以被重载。
2、对于运算符重载为类的友元函数,VC++6.0不允许在声明重载运算符之前使用using namespace std,多以分别列出对cout和endl的使用:using std::cout;using std::endl;。
3、重载为类的成员函数语法形式为:
4、重载为类的有原函数的定义格式:
5、无法声明一个抽象类的对象。
抽象类:
1、 带有纯虚构函数的类被称为抽象类。纯虚构函数的定义形式:
virtual 函数类型 函数名(参数表)=0;
2、 抽象类不能用作参数类型、函数返回值或强制类型转换;
3、 可以定义一个抽象类的指针和引用。通过抽象类的指针和引用,可以指向并访问各派生类成员,这种访问具有多态特征。
成员函数运算符与友元函数运算符的特点:
1、 一般情况下,单目运算符最好重载为类的成员函数;双目运算符最好重载为类的友元函数。
2、 一些双目运算符不能重载为类的友元函数:=、()、[ ]、->。
3、 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。
4、 如果一个运算符的操作需要对象的状态,选择重载为成员函数较好。
5、 若运算符所需的操作数(尤其是第一个操作数)希望有隐式转换,则只能选用友元函数。
6、 当运算符函数是一个成员函数时,最左边的操作数(或者只是最左边的操作数)必须是运算符类的一个类对象(后者是对该类对象的引用)。如果左边的操作数必须是一个不同的对象,或者是一个基本数据类型的对象,该运算符函数必须作为一个友元函数来实现。
7、 当需要重在运算符的运算具有可交换性时,选择重载为友元函数。
运算符被重载的规则:
1、 重载后运算符的优先级与结合性不会改变。
2、 不能改变原运算符操作数的个数。
3、 不能冲在c++中没有的运算符。
4、 不能改变运算符的原有语义。
类的成员函数的运算符重载规则:
① 双目运算符重载为类的成员函数时,函数只显式说明一个参数,该形参是运算符的右操作数。
② 前置单目运算符重载为类的成员函数时,不需要显式说明参数,即函数没有形参。
③ 后置单目运算符重载为类的成员函数时,为了与前置单目运算符区别,函数要带有一个整型形参。
类的友元函数的运算符重载规则:
1双目运算符 B重载后,表达式oprd1 B oprd2等同于operator B(oprd1,oprd2 );
②前置单目运算符 B重载后,表达式 B oprd等同于operator B(oprd ) ;
③后置单目运算符 ++和–重载后,表达式 oprd B 等同于operator B(oprd,int )
虚函数:
1、 虚函数不能使静态函数,也不能是友元函数。
2、 内联函数是不能在运行中动态确定其位置的,即使虚函数在类的内部定义,编译时,仍将其看做非内联的。
3、 只有类的成员函数才能说明为类的虚函数;虚函数仅适合于有继承关系的类对象。
4、 构造函数不能是虚函数,析构函数可以是虚函数,而且通常声明为虚函数。
※动态联编只能通过指针或引用标志对象来操作函数。如果采用一般类型的标志对象来操作虚函数,则将采用静态联编方式调用虚函数。
类模板定义语法:
模板类的成员函数在类外定义的语法格式:
类模板实例化、建立对象的语法形式:
※类模板的类型参数也可以采用默认值。带默认模板参数值的类模板的默认值给出顺序为从右向左,实参值结合顺序为从左向右。
函数模板的定义形式:
函数显示实例化的格式:函数名<具体函数名1, 具体函数名2,…,常量表达式>(实参表)