二.构造/析构/赋值运算
来源:互联网 发布:vivo网络制式怎么查看 编辑:程序博客网 时间:2024/05/18 17:59
条款05:了解C++默默编写并调用哪些函数
如果写一个空类:
class Empty{};
会被编译器处理成:
class Empty
{
public:
Empty()
{
}
~Empty()
{
}
Empty( const Empty& rhs )
{
}
Empty& operator=( const Empty& rhs )
{
}
};
这些函数都是public且为inline,唯当这些函数需要被调用,它们才会被编译器创建出来。
Empty e1; //default构造函数
Empty e2( e1 ); //copy构造函数
e2 = e1;//拷贝运算符
default构造函数和析构函数主要是给编译器一个地方放置幕后代码,像是调用base class和non-static成员变量的构造函数和析构函数。注意,编译器产出的析构函数式一个non-virutal,除非这个class的base class自身声明有virtual析构函数(这种情况下这个函数的虚属性主要来自于base calss)
至于copy构造函数和copy assignment操作符,编译器创建的版本只是单纯的将来源对象的每一个non-static成员变量拷贝到目标对象。
如果打算在一个内含ref成员的class内支撑赋值操作,则必须自己定义赋值操作符。面对内含const成员的class,编译器也会拒绝赋值操作。还有一种情况,如果某个base class将copy assignment操作符声明为一个private,编译器将拒绝为其derived classes生产一个copy assignment操作符,毕竟编译器为derived classes所生产的copy assignment操作符想象中可以处理base classes部分,但它们当然无法调用derived classes无权调用的成员函数。
请记住:
1.编译器可以为class创建default,copy构造函数copy assignment操作符,析构函数。
条款06:若不想使用编译器自动生产的函数,就该明确拒绝
明确声明一个private版本的,这样就阻止了编译器暗自创建其专属版本,同时也阻止了人们调用它们。
一般而言这样是不安全的,因为成员呢函数和friend函数还是可以调用private函数。除非你够聪明不去定义它们,那么如果某些人不慎调用任何一个,会获得一个链接错误。这一伎俩在C++ Iostream程序库中阻止copying行为。
将连接器错误移植到编译器是可能,仅仅需要专门设计一个base class。
class UnCopyable
{
protected:
UnCopyable();
~UnCopyable(); //允许构造和析构
private:
UnCopyable( const UnCopyable& );
UnCopyable& operator=( const UnCopyable& ); //阻止copy
};
为了阻止拷贝,仅仅继承UnCopyable就行了
class HomeForSale : private UnCopyable
{
};
也可以使用Boost提供的版本,class名为noncopyable。
条款07:为多态基类声明virtual析构函数
C++指出,当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义----实际执行时通常发生的是对象的derived成分没有被销毁。而其base部分销毁了。
于是在工厂模式中单纯的通过删除base指针会造成一个局部销毁,这可能是形成资源泄露,败坏的数据结构以及在调试器上浪费时间的途径。
消除这个问题的做法:给base class一个virtual析构函数,此后删除derived class对象就会销毁整个对象,包括derived class的成分。
同时,任何class只要带有virtual函数都几乎确定应该也有一个virtual析构函数。
如果class不含virtual函数,通常表示它并不试图被用作一个base class.当一个class不企图被作为base class,令其析构函数为virtual往往是一个馊主意。
欲实现virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。这份信息通常是由一个vptr指针指出,vptr指向一个函数指针构成的数组,称为vtbl。每一个带有virtual函数的class都有一个相应的vtbl。当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指的那个vtbl------编译器在其中寻找适当的函数指针。
这样使用virtual函数的class会增加对象的体积,且其对象也不再和其他语言(C)内的相同声明有着一样的结构,因此就不再可能把它传递到其他语言所写的函数中,除非你明确补偿vptr------那属于实现细节,也因此不再具有移植性。
只有当class内含有至少一个virtual函数,才为它声明virtual析构函数。
即使class完全不带virtual函数,被non-virtual析构函数问题给咬伤还是有可能。
class SpecialString: public std::string//string有个non-virtual析构函数
{
};
SpecialString* pss = new SpecialString( "Hello" );
string* ps;
ps = pss;
delete ps;//未有定义,*ps中的specialString会资源泄露,因为SpecialString析构函数未被调用。
相同的分析适用于任何不带virtual析构函数的class,包括所有的STL容器。所以,企图继承一个标准容器或任何其他带有non-virtual函数的Class,拒绝诱惑吧。(很不幸,C++没提供类似java的final class或C#的sealed class那样的禁制派生机制。)
有时候令class带一个pure virtual析构函数,可能颇为便利。
pure virutal函数导致abstract class-------也就是不能被实体化,也就是说不能为那种类型创建对象。然而有时候你希望拥有抽象class,但手上没有任何pure virtual没怎办?由于抽象类总是企图被当做一个base class来用,而又由于base class应该有个virtual析构函数,并且由于pure virtual函数会导致抽象class,因此解法很简单:为你希望它成为抽象的那个class声明一个pure virtual析构函数。且必须为这个pure virtual析构函数提供一份定义。
析构函数的运作方式为:最深层派生的那个class其析构函数祖先被调用,然后其每一个base class的析构函数被调用。
给base class一个virtual析构函数,这个规则只适用于polymorphic base class身上。这种base class的设计目的是为了用来通过base class接口处理derived class对象。并非所有的base class的设计目的都是为了多态用途,因此它们不需要virtual 析构函数。
请记住:
1.polymorphic base class应该声明一个virtual析构函数。如果class带有任何virtual函数,他就应该有一个virtual析构函数。
2..class的设计目的如果不是作为base class使用,或不是为了具备多态性,就不应该声明为virtual 析构函数。
条款08:别让异常逃离析构函数
C++并不禁止析构函数吐出异常,但它不鼓励你这样做:
- 二.构造/析构/赋值运算
- Effective C++(二)构造/析构/赋值运算
- EffectC++(二):构造/析构/赋值运算
- Effective C++ <二>:构造,析构,赋值运算
- 构造/析构/ 赋值运算
- 构造,析构,赋值运算
- 【读书笔记】Effective C++-2 构造/析构/赋值运算(之二)
- Effective C++笔记: 构造/析构/赋值运算(二)
- effective c++读书笔记二——构造/析构/赋值运算
- Effective C++(二)构造/析构/赋值运算
- Effective C++学习笔记二(构造/析构/赋值运算)
- Effective C++ 笔记二构造/析构/赋值运算
- Effective C++ — 构造/析构/赋值运算(二)
- Effective C++之二:构造/析构/赋值运算
- 2.构造/析构/赋值运算
- [C++] 构造/析构/赋值运算
- 2构造/析构/赋值运算
- 2 构造、析构、赋值运算
- This server could not verify that you are authorized to access the document requested.
- uchome 不用每次都更新缓存的方法
- linux 中截屏
- android视频播放器关键代码
- UITextField输入事件
- 二.构造/析构/赋值运算
- 在Azure虚拟机上开启OpenVPN
- getline和ifstream<<读文件的方式
- Win32多线程编程 — 线程局部存储
- Storm安装配置(单机版)笔记
- 自己写操作系统2——进入保护模式
- javascript之jQuery ajax 操作
- 关于.net邮件开发
- jquery easyui datagrid分页显示数据