《Effective C++》学习笔记(三)
2014-08-25 15:26
344 查看
原创文章,转载请注明出处:/article/8316762.html
一般情况下编译器产出的析构函数是non-virtual的,但如果这个类的基类(base class)自身声明有virtual析构函数,那就另当别论了。
如果在类中有任意构造函数,编译器不会再为它创建default构造函数。
总结:
编译器可以暗自为class创建default构造函数、copy函数、copy assignment操作符,以及析构函数。
但这样并不是绝对的安全,因为成员函数和友元函数依旧可以调用它,当然,依旧有法可依。
如果我们只声明它们,不去定义,那么如果别人调用它们将会获得一个连接错误。
当然,这样我们横跨了编译期和连接期,想要将连接期报错提前到编译期也是可以的。
Uncopyable的实现与运用颇为微妙,包括不一定需要以public继承它,以及Uncopyable的析构函数不一定得是virtual等等,但是这样将有可能造成多重继承,而多重继承有时会阻止空白基类最优化(empty base class optimization)。
当然,到目前为止,所讲得内容仅仅止步于c++11发布前,C++11发布后为拒绝编译器的“好意”提供了新的方法:
总结:
1)为驳回编译器自动提供的机能,可以将相应的成员函数声明为private并且不予实现。使用像Uncopyable这样的base class也是一种做法。
2)支持C++11的编译器上也可以将成员函数定义成delete。
从上一段话的关键字中不难知道,解决办法便是给base class一个virtual析构函数,virtual析构函数的目的是允许derived class的实现得以客制化。任何class只要带virtual函数都几乎确定它也应该有一个virtual的析构函数。
如果claa不含virtual函数,通常表示它并不会被用作一个基类。当class不起图呗当做基类,令其析构函数为virtual是个馊主意。
virtual函数之所以能实现多态,决定什么时候调用哪一个virtual函数,是因为它携带着一份特殊信息,由一个所谓的vptr(virtual table pointer)指出。vptr指向一个由函数指针数组构成的数组,称作vtbl(virtual table),每一个带有virtual函数
总结:
1)带多态性质的(polymorphic)基类(base class)应该声明一个virtual析构函数。如果class带有任何virtual函数,他就应该拥有一个virtual析构函数。
2)Classes的设计目的如果不是作为基类使用,或不是为了具备多态性,就不该声明virtual析构函数。
闲谈
从北戴河旅游归来,该收心继续上班了,接下来将继续学习《Effective C++》,今天看的是构造/析构/赋值运算部分。条款05:了解C++默默编写并调用那些函数
当经过编译器处理后,并没有绝对的空类,例如:class Empty{ };编译器会为它声明一个default构造函数,一个copy构造函数、一个copy assignment操作符,一个析构函数:
class Empty { public: Empty() { ... }; Empty(const Empty &rhs) { ... }; ~Empty() { ... }; Empty& operator=(const Empty &rhs) { ... }; }注意!!!仅仅是被声明出来了,只有当这些函数被真正调用的时候,它们才会被编译器创建出来。
一般情况下编译器产出的析构函数是non-virtual的,但如果这个类的基类(base class)自身声明有virtual析构函数,那就另当别论了。
如果在类中有任意构造函数,编译器不会再为它创建default构造函数。
总结:
编译器可以暗自为class创建default构造函数、copy函数、copy assignment操作符,以及析构函数。
条款06:若不想使用编译器自动生成的函数,就应该明确拒绝
世界上没有两片完全相同的叶子,所以当我们声明一个叶子对象,并希望通过这个叶子对象拷贝出另一片叶子,这个行为是不合法的。Leaf l1; Leaf l2; Leaf l3(l1); // 企图拷贝l1,不应该通过编译 l3 = l2; // 企图拷贝l2,也不应该通过编译为了使这个机能实现,阻止编译器自动生成,我们可以将copy构造函数和copy assignment操作符定义为private。
但这样并不是绝对的安全,因为成员函数和友元函数依旧可以调用它,当然,依旧有法可依。
如果我们只声明它们,不去定义,那么如果别人调用它们将会获得一个连接错误。
class Leaf { public: ... private: ... Leaf(const Leaf&); Leaf& operator=(const Leaf&); }
当然,这样我们横跨了编译期和连接期,想要将连接期报错提前到编译期也是可以的。
class Uncopyable { protected: Uncopyable() {} //允许派生对象构造和析构 ~Uncopyable() {} private: Uncopyable(const Uncopyable&); //但阻止copying Uncopyable& operator=(const Uncopyable&); } class Leaf: private Uncopyable { ... }
Uncopyable的实现与运用颇为微妙,包括不一定需要以public继承它,以及Uncopyable的析构函数不一定得是virtual等等,但是这样将有可能造成多重继承,而多重继承有时会阻止空白基类最优化(empty base class optimization)。
当然,到目前为止,所讲得内容仅仅止步于c++11发布前,C++11发布后为拒绝编译器的“好意”提供了新的方法:
class Leaf { public: ... private: ... Leaf(const Leaf&) = delete; Leaf& operator=(const Leaf&) = delete; }
总结:
1)为驳回编译器自动提供的机能,可以将相应的成员函数声明为private并且不予实现。使用像Uncopyable这样的base class也是一种做法。
2)支持C++11的编译器上也可以将成员函数定义成delete。
条款07:为多态基类声明virtual析构函数
当一个对象定义在堆中,同时它拥有一个有着non-virtual析构函数的基类,当这个对象被delete的时候,特属于派生类(derived class)的部分并没有被销毁,于是会照成局部销毁的现象。从上一段话的关键字中不难知道,解决办法便是给base class一个virtual析构函数,virtual析构函数的目的是允许derived class的实现得以客制化。任何class只要带virtual函数都几乎确定它也应该有一个virtual的析构函数。
如果claa不含virtual函数,通常表示它并不会被用作一个基类。当class不起图呗当做基类,令其析构函数为virtual是个馊主意。
virtual函数之所以能实现多态,决定什么时候调用哪一个virtual函数,是因为它携带着一份特殊信息,由一个所谓的vptr(virtual table pointer)指出。vptr指向一个由函数指针数组构成的数组,称作vtbl(virtual table),每一个带有virtual函数
总结:
1)带多态性质的(polymorphic)基类(base class)应该声明一个virtual析构函数。如果class带有任何virtual函数,他就应该拥有一个virtual析构函数。
2)Classes的设计目的如果不是作为基类使用,或不是为了具备多态性,就不该声明virtual析构函数。
相关文章推荐
- 《Effective C++》学习笔记条款27 尽量少做转型动作
- 《Effective C++》学习笔记(一)
- 《effective c++》学习笔记(一)
- 《effective c++》学习笔记(四)
- 《effective c++》学习笔记(五)
- 《Effective C++》学习笔记——条款26
- 《effective c++》学习笔记(七)
- 《Effective C++》学习笔记(1)
- 《Effective C++》学习笔记条款02 尽量以const,enum,inline替换#define
- 《effective c++》学习笔记(一)
- 《effective c++》学习笔记(四)
- 《effective c++》学习笔记(四)
- 《effective c++》学习笔记(五)
- 《effective c++》学习笔记(七)
- 《Effective C++》学习笔记——条款30
- 《Effective C++》学习笔记——条款39
- 《Effective C++》学习笔记——条款40
- 《Effective C++》学习笔记条款03 尽可能使用const
- 《Effective C++》学习笔记条款19 设计class犹如设计type
- 《Effective C++》学习笔记——条款45