1.基础议题
条款01:仔细区别points和references
指针和引用有很多相似的地方,但是用法还是有区别。所以一般还是不会搞混。
这里需要注意的是,points是可以为null的但是reference必须得有初始时。这可能也意味着很多时候,使用引用效率会高于使用指针。因为使用一个指针之前,一定要判断它是否被初始化。
直接对一个引用取地址,得到的是和被引用数一样的地址。利用gdb反汇编,分析引用值存储的栈空间地址,查看其值,可以知道,引用本质上就是用指针实现的。使用的是const point。
条款02:最好使用c++转型操作符
这个条款在effective c++中已经提过了,c++提供了4种新式转型:
static_cast<>:类似于之前的C转型动作
const_cast<>:去除const和volitileness
dynamic_cast<>:将base class转化为drived class的转型
reinterpret_cast<>:这个转型我也不是很懂,例子里是可以将point转为int
结论就是:c++转型操作又臭又长,很不好使用。但是提供严谨意义与易辨识度。并且让转型操作又臭又长,未必不是一件好事。
条款03:绝对不要以多态的方式处理数组
对于多态不是很陌生,但是看到这个条款的时候,还是没有马上想到相应的情况。
如果只用base指针指向drived对象,这是肯定没问题的。如果析构函数定义为virtual的,delete base也是正确。但是如果定义一个base数组,数组中每个指针都指向drived对象。在delete []数组的时候,就会出问题。
这里首先会调用所有对象的析构函数,然后释放空间。这是c++中的未定义行为,base指针删除一个由drived classes object定义的数组。
然后还有一种情况也会出问题。这里需要知道的核心部分还是:多态是动态绑定,但是函数参数是静态绑定。在编译期,编译器就会为静态绑定设计好代码。如果一个函数的参数是base数组,但是传入了一个drived 数组,就可能会出问题。
如下代码,每次i+1,array地址会加sizeof(base),而不是sizeof(drived),这就会出问题
条款04:非必要不提供 default construction
这个条款首先说没必要的时候,不提供默认构造函数。但是马上却列出了不提供默认构造函数会出现的很多问题。所以这个条款看起来有点矛盾
首先问题是如果没有默认构造函数,无法直接调用new []构造对象数组。处理方法是先构造对象指针数组,然后再单个调用构造函数。或者是用placement new
还有一个问题就是,如果基类没有默认构造函数。派生类构造的时候,就必须调用基类带参数的构造函数。如果继承比较复杂,这将很痛苦
最后结论是,如果默认构造函数能够提供对象的所有字段都被完整初始化的确保,那么提供一个默认构造函数是可以的。否则,不要提供一个默认构造函数
Last updated
Was this helpful?