第7章 类
1. 引入const成员函数(C++ Primer P231-232)
C++类的常量对象是无法调用非const成员函数的,如果想让常量对象调用某个成员函数,必须声明成const:
2. 一个类的尾后const成员函数如果返回*this,那么其返回类型必然是const 类名 & 前面这个const是不能少的.否则无法通过编译.
3. 默认构造函数P235-236
编译器只有在发现类中不包含任何构造函数的情况下,才会为我们合成一个默认的构造函数,且该函数对于类中的成员执行默认初始化(如果类成员具有类内初始值就不执行默认初始化了).
对于内置类型成员,局部对象默认初始化赋予随机值,全局对象默认初始化赋予0.
对于类类型成员,默认初始化调用该类的默认构造函数.
编译器有可能不能给没有构造函数的类合成一个的.假如A类没有默认构造函数,但是A类中包含一个B类的对象成员b,且B类没有默认构造函数,此时编译器将无法用合成的构造函数初始化A类对象中的成员b,所以此时A类将不存在合成的默认构造函数:
如果一个类的构造函数只给部分成员赋予了初值,那么剩下的成员将获得一个默认值(如果有类内初始值,则直接初始化,否则执行默认初始化).
4. 拷贝与赋值的区别 P239
对象在几种情况下会被拷贝:初始化变量,以值的方式传递或返回一个对象.
我们使用了赋值运算符时,会发生对象的赋值操作.
5. 友元P241
类A定义了两个友元,分别是函数print() 和类B,所以在函数print()内部或在类B的内部可以访问类A的私有成员x.
注意:如果你想直接cout<<b.a.x<<endl;的话 还是错的,因为x是私有的,就算类A是B的友元,你也不能直接访问a的私有成员. 友元的含义不过是指在类或函数的内部你可以访问其他类的私有成员.
友元再探:
假设有A类和B类,现在想在B类中把A类的一个函数print()定义成友元,应该怎么定义先后顺序?
应遵循上面的顺序:先声明B类,然后再定义A类,但是A类的print函数只能声明,不能定义.
可以这样理解:
A类定义先于B类定义(但此时print()仅声明不定义): 既然B类要把一个A类的成员函数print()作为友元,那么明显A类的定义要先于B类,因为这样你才能在定义B类的时候能引用A类的print()成员函数.
B类声明先于A类定义: B类其次由于print()成员函数有B类的形参,所以你需要在定义A类之前,把class B声明一下,才行.
B类定义先于print()函数定义: 由于print()函数的定义中用到了B类的成员,所以在你定义print()函数时,B类必须已经完全定义了.
友元函数声明:
假设类A用friend声明了友元函数print(). 此时print()可以先不声明,但是任何类A的代码也不可以调用print(). 只有等print()函数在全局声明之后,类A才能调用print()函数使用. 也就是说print()函数何时能被使用,只与它是否被正常声明有关.
6. 可变数据成员(mutable关键字)P245 就算是const对象,mutable成员也可以被改变.
a是一个常量对象, a只能调用const成员函数.
7. 假设class A有一个set方法和一个print()方法,我们什么情况下能如下使用: a.set(10).set(100).print(); 当set()返回 *this的引用时!
因为点运算符是左结合的,所以左边先计算. 此时set返回*this的引用,所以可以继续调用其他成员函数.
注意:如果set()函数是const的,那么它返回的*this 就是一个const对象,那么a.set()就不能调用非const的print()函数. 关于这点可见P247-248页.
8. 不完全类型:一个类只有声明,但是却还没有定义.P250
可以定义指向该类型的指针或引用,也可以声明把以不完全类型为参数或返回值的函数. 但是不可以定义不完全类型的对象.所以:
一个类可以包含指向它自身类型的指针或引用
但是不能包含自身类型的对象.
9. 类型名作用域:P255
类中定义的类型名可以覆盖类外定义的类型名,前提是当前定义语句之前没有使用过类外的类型名:
由于定义val时,已经用了money定义,所以接着定义新money类型是错的. 如果money新类型放在第4行的话,那么就是正确的.
10. 某些类的构造函数必须初始化: const成员, 引用, 或某些未提供默认构造函数的类类型.因为如果不初始化,那么这些成员就没有意义.
上面的类A构造函数没有对v2和v3执行初始化,所以是错的.A的构造函数应该对v2和v3执行初始值列表初始化.而不应该在构造函数中直接赋值(赋值不是初始化).
11. 构造函数中成员的初始化顺序是按照它们在类中定义的先后顺序的,而不是按照初始值列表中的成员顺序:
v1先初始化,所以v1(v2)后,v1将是一个随机值.v2后初始化,所以v2将是500.
12. 委托构造函数用法(P261,经测试 非C++11编译器也能用)
注意:假设构造函数1委托了构造函数2构造对象,那么构造函数1就算定义在构造函数2之前,1函数照样能调用2函数,
13. 类对象被默认初始化或值初始化时自动执行默认构造函数,所以尽量给每个类都写一个默认构造函数,否则容易出现错误.
14. 转换构造函数->隐式的类类型转换(P295)
如果构造函数只接受一个参数,那么它实际上定义了转换为此类类型的隐式转换机制. 即在需要该类对象的地方,我们可以使用那个参数替代.
上面A类中,分别用100和cin替代了A类的对象.
只允许一步类类型转换! 但是内置类型的转换支持多步.即上面的语句可以写成 a1=a1+100.3; 先将100.3转成int(内置转换),然后将int转成类A对象(类类型转换).
上面代码想将100转成B的对象,然再转成A的对象将出错.
抑制转换构造函数的隐式转换:explicit关键字
用了explicit关键字的单参数构造函数不会自动执行了(explicit对多参数构造函数无任何影响).且初始化的时候,explicit的构造函数只能直接初始化,不能赋值初始化了.
explicit关键字只能出现在类内部构造函数声明处.
15. 类的静态成员变量与静态成员函数
类的静态成员变量必须在类的外部定义和初始化一次,否则无法正确使用.
原文地址:http://blog.csdn.net/u013480600/article/details/44109739