EC读书笔记系列之3:条款5、条款6、条款7
条款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中创建一个对基类析构函数的调用动作,所以你必须为这个函数提供一份定义,否则连接器会抱怨)
EC读书笔记系列之3:条款5、条款6、条款7的更多相关文章
- EC读书笔记系列之12:条款22、23、24
条款22 将成员变量声明为private 记住: ★切记将成员变量声明为private.这可赋予客户访问数据的一致性.可细微划分访问控制.允诺约束条件获得保证,并提供class作者以充分的实现弹性. ...
- EC读书笔记系列之16:条款35、36、37、38、39、40
条款35 考虑virtual函数以外的其他选择 记住: ★virtual函数的替代方案包括NVI手法及Strategy模式的多种形式.NVI手法自身是一个特殊形式的Template Method模式 ...
- EC读书笔记系列之1:条款1、条款2、条款3
条款1:视C++为一个语言联邦 记住: ★C++高效编程守则视状况而变化,这取决于你使用C++的哪一部分 C: Object-oriented c++: Template c++: STL 条款2:尽 ...
- EC读书笔记系列之20:条款53、54、55
条款53 不要轻忽编译器的警告 记住: ★严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取“无任何警告”的荣誉 ★不要过度依赖编译器的报警能力,∵不同的编译器对待事情的态度 ...
- EC读书笔记系列之19:条款49、50、51、52
条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...
- EC读书笔记系列之18:条款47、48
条款47 请使用traits classes表现类型信息 记住: ★Traits classes使得“类型相关信息”在编译期可用.它们以templates和“templates特化”完成实现 ★整合重 ...
- EC读书笔记系列之17:条款41、42、43、44、45、46
条款41 了解隐式接口与编译器多态 记住: ★classes和templates都支持接口和多态 ★对classes而言接口是显式的(explicit),以函数签名为中心.多态则是通过virtual函 ...
- EC读书笔记系列之15:条款32、33、34
条款32 确保你的public继承塑模出is-a关系 记住: ★public继承意味着is-a.适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个deriv ...
- EC读书笔记系列之14:条款26、27、28、29、30、31
条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...
- EC读书笔记系列之11:条款20、21
条款20 宁以pass-by-reference-to-const替换pass-by-value 记住: ★尽量以pass-by-reference-to-const替换pass-by-value.前 ...
随机推荐
- 【UVA】1449-Dominating Patterns(AC自己主动机)
AC自己主动机的模板题.须要注意的是,对于每一个字符串,须要利用map将它映射到一个结点上,这样才干按顺序输出结果. 14360841 1449 option=com_onlinejudge& ...
- Android----获取activity上所有的控件
/** * @note 获取该activity所有view * @author liuh * */ public List< ...
- EditText默认不显示光标,不可编辑,点击它,进入编辑状态,光标显示
设置EditText不可编辑,光标不可见: et.setCursorVisible(false); 设置EditText可编辑,光标可见: et.setOnClickListener(new OnCl ...
- WindowsForm 计算器
计算器 可以分一下类 数字键 + - * / % =和撤销 归零C最简单 下面看一下计算器具体的代码 using System; using System.Collections. ...
- PHP的五种常见设计模式
工厂模式 最初在设计模式 一书中,许多设计模式都鼓励使用松散耦合.要理解这个概念,让我们最好谈一下许多开发人员从事大型系统的艰苦历程.在更改一个代码片段时,就会发生问题,系统其他部分 —— 您曾认为完 ...
- hibernate中先建表还是先建实体类
在实际工作中往往是先建表然后再生成类原因:建好数据库表之后往往要对数据表进行一些优化,比如说建索引,比如说建中间表,比如建视图.如果先建类的话这些优化是无法生成的
- mysql性能优化学习笔记(2)如何发现有问题的sql
一.使用mysql慢查询日志对有效率问题的sql进行监控 1)开启慢查询 show variables like ‘slow_query_log’;//查看是否开启慢查询日志 ...
- html5 OPOA
1.0 one page one application 一个应用只有一个页面,对用户的表现来说的. 2.0 起源于web的MIS系统 MIS(管理信息系统) 3.0 银行客户端 4. ...
- firemonkey打开子窗体(匿名回调函数)
procedure TForm1.Button1Click(Sender: TObject);varChildForm: TForm2;beginChildForm := TForm2.Create( ...
- android PopupWindow显示位置
PopupWindow的显示及位置设置 window.showAtLocation(parent, Gravity.RIGHT | Gravity.BOTTOM, 10,10); 第一个参数指定Pop ...