首页 > 代码库 > 《Effective C++》学习笔记(三)
《Effective C++》学习笔记(三)
原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38816913
闲谈
从北戴河旅游归来,该收心继续上班了,接下来将继续学习《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++》学习笔记(三)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。