第十一、十二、十三、十四章 引用和拷贝构造函数,运算符重载,继承组合等
1. C++中指针的类型检查更为严格。
2. 因为默认拷贝构造函数采用位拷贝,所以对包含指针的对象,必须自己定义拷贝构造函数,进行真正的复制,避免浅拷贝。
3. 防止对象按值传递的方法之一:定义一个私有拷贝构造函数,但什么也不做。
4. 运算符重载只是为了使语法方便,实质仍是函数调用。只有自定义类型的运算符才可重载,比如,不可重载两个int型的+符号。运算符重载时的参数个取决于:(1)运算符是几元的?(2)运算符重载是全局函数,还是成员函数?(3)++、--运算符重载时,为区别前后缀,会增加一个int参数,有参数时为后缀。
5. “<<””>>”作为输入输出流运算时,可以用全局函数方式对之进行重载,使之按要求输出对象。
6. 当Mytype b; Mytype a=b;时会调用拷贝构造函数,而若a之前定义过,则会调用operator =,所以需要重载之。编译器自动生成赋值函数与拷贝构造函数原则一致。
7. 如果定义了一个构造函数,这个构造函数能把另一个类型的对象(或引用)作为它的唯一参数,那么这个构造函数允许编译器进行自动类型转换,如果此构造函数前加了explicit关键字,则要求用户进行显式类型转换,禁止自动类型转换功能。
8. 使用7中提到的方法,只能目的类执行转换,而无法实现自定义类型向到内置类型的转换,这时只有运算符能做到,这个函数通过operator关键字,后跟想转换成的类型,如:operator Three() const{return Three(x);}(其中x为其成员变量,Three为目的类型,operator Three()为public成员函数)。
9. 多个版本的类型转换可能造成冲突,因此最好只有其中一种,并且可考虑makeA(); makeB();之类的函数实现。
10. 对于一个未写任何方法的类,编译器为它实现的方法包括:构造、析构、赋值操作符、取地址操作符、拷贝构造函数。
11. 定义数组与对象时,左式一样,但释放不同,如:
MyType * fp=new MyType[100];
MyType * fp2=new MyType;
delete [] fp;
delete fp2;
12. 当系统耗尽时,new操作会调用系统默认的new_handler函数,可以通过包含new.h并通过set_new_handler()来设置自己定义的new_handler函数。因此,如果想自己实现一个垃圾收集器,可以在此处扩展,每次分配失败时,进行垃圾收集,然后再执行分配。
13. 可以重载new与delete运算符来实现自己想要的内存分配策略,如:加入分配地址记录及大小等查内存泄漏的功能。但重载只影响内存分配,不影响构造和析构函数调用等。同理,new[]、delete[]也可以重载。
14. 构造函数与析构函数的形式严格相反!任何类调用构造函数之前,都先调用父类构造函数、然后是子对象构造函数,对于多个子对象,调用它们构造函数顺序与声明一致。
15. 任何子类中定义的与父类的同名函数,都会隐藏掉父类函数。因此,如果真要定义同名函数,就要确定它们确实代表同样的含义,用虚函数机制实现之,否则不应该定义同名不同义的函数。
16. 构造函数、析构函数及operator =不可被继承。自动类型转换可被继承,因为子类可向父类转换,除赋值运算符之外的运算符也可继承到派生类中。对于不可被继承的函数,最好显式定义它们,以免编译器自动实现时达不到期望。
17. 静态成员函数与非静态成员函数的异同点:
(1)都可以继承到派生类中;
(2)若重定义了静态成员函数同名的静态方法,则的被隐藏(参考15);
(3)若在子类中改变了基类某一静态成员函数的特征,所有使用该函数名的基类版本都将会被隐藏。然而,静态函数不可以是虚的,静态成员函数作用在于不需要生成对象即可用,因此可在无虚函数表时访问,即不可以是虚的。
18. 当想使基类派生而来的部分public成员在派生类中隐藏(即为private),可以使用默认的private继承方式,而在子类中将想公开的基类公有成员用public修饰,如:public using Pet::eat;//Pet为基类名,eat为方法名。