标签:
条款5:了解C++默默编写并调用哪些函数
记住:
★编译器可以(仅仅是可以,并非必须,仅当程序中有这样的用法时才会这么做!!!)暗自为class创建default构造函数,copy构造函数,copy assignment操作符以及析构函数。
--------------------------------------------------------------------------------------------------------------------------------------------
当你写一个空类,编译器会为其声明(仅仅是声明!!!)default构造函数,copy构造函数,copy assignment操作符和析构函数,它们都是public且inline。唯有当这些函数被需要(被调用),它们才会被编译器真正创建出来。
对于copy constructor和copy assignment操作符,编译器创建的版本只是单纯地将来源对象的每个non-static成员变量拷到目标对象。
特殊情形:
对于内含reference或者const成员的class,编译器会拒绝为其生成copy assignment操作符。若你打算这种类支持assignment操作,就必须自己定义copy assignment操作符。还有一种情况:若某个bases classes将copy assignment操作符声明为private,编译器将拒绝为其derived classes生成一个copy assignment操作符。毕竟编译器为derived classes所生的copy assignment操作符想象中可以处理base class成分,但它们当然无法调用derived class无权调用的成员函数。
条款6 若不想使用编译器自动生成的函数,就该明确拒绝
记住:
★为驳回编译器自动(暗自)提供的功能,可将相应的成员函数声明为private并且不予实现。使用像Uncopyable(下面会讲)这样的base class也是一种做法。
--------------------------------------------------------------------------------------
借由声明一个成员函数,可阻止编译器暗自创建其专属版本(注意所有编译器产出的函数都是public);而令这些函数为private,可以阻止人们调用。但即使这样,member functions和friend函数还是可以调用你的private函数,解决方法是,仅声明这个private函数而不去定义,这样在不慎调用时会发生连接错误。(C++ iostream程序库中阻止copying行为就是这么做的!!!)
另一种方法所谓的可将连接期错误移至编译期(好事,毕竟越早侦测出错误越好):
class Uncopyable { //Uncopyable的使用颇为微妙!!! protected: Uncopyable() {} ~Uncopyable() {} private: Uncopyable( const Uncopyable & ); Uncopyable& operator=( const Uncopyable& ); }; class HomeForSale : private Uncopyable { //这样这个class就不用再声明私有的copy构造函数和 //copy assignment操作符 };
这样的话,只要任何人--甚至是member函数或friend函数--尝试拷贝HomeForSale 对象,编译器便试着生成一个copy构造函数和一个copy assignment操作符,而且这些函数的“编译器生成版”会尝试调用其base class的对应兄弟,而那些调用会被编译器拒绝(这就将本在在连接期的错误移到了编译期!!!),∵其base class的拷贝函数是private。不过这样做的一个问题是:使用这项技术可能导致多重继承(∵往往还可能需要继承其他class),而多重继承有时会阻止empty base class optimization(EBO)。
条款7 为多态基类声明virtual析构函数
记住:
★带多态性质的base classes应该声明一个virtual destructor。若class带有任何virtual函数,它就应该拥有一个virtual destructor。
★classes的设计目的若不是作为base classes使用,或不是为了具备多态性,就不该声明virtual destructor。
-----------------------------------------------------------------------------------------------------------------------------------
当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,实际执行时通常发生的是对象的derived成分没被销毁(局部销毁现象)。
当class不企图被当作base class,就无需令其析构函数为virtual。因为这样会增加vptr所占用的空间,解释如下:
欲实现出virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。此份信息通常由一个所谓vptr(virtual table pointer)指针指出。vptr指向一个函数指针数组(称vtbl,virtual table);每一个带有virtual函数的class都有一个相应的vtbl。当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指的那个vtbl,编译器会在其中寻找适当的函数指针。
拒绝 继承一个标准容器或任何其他“带有non-virtual析构函数”的class 这样的诱惑!!!
最好为抽象基类声明一个pure virtual destructor并提供空白定义,三个理由:
由于有pure virtual函数,所以构成抽象基类;
由于有个virtual destructor,所以无需担心析构函数的问题;
至于为什么提供空白定义,可以解释如下:
(析构函数的运作方式是,最深层派生的那个class其析构函数最先被调用,然后是其每一个base class的destructor被调用。编译器会在基类的derived classes的destructor中创建一个对基类析构函数的调用动作,所以你必须为这个函数提供一份定义,否则连接器会抱怨)
标签:
原文地址:http://www.cnblogs.com/hansonwang99/p/4915833.html