Effective C++记录(精简版)

Effective C++记录(精简版)


学习目标:如何高效使用 C++的建议。

2.1.习惯C++

2.1.1.条款1 视c++为一个语言联邦

原因:解决语法规则混乱的情况。每个子语言里,特性简单明了。

四个次语言:
C
Object-Oriented C++
Template C++
STL

1、高效编程守则视状况变化,取决于你是用C++的哪一部分。
如:对于内置类型(C)而言,pass by value通常比pass by reference高效。但对于Object-Oriented C++而言,引用更高效。

2.1.2.条款2 尽量以consts、enum、inline替换#define

使用consts替代的原因:把变量纳入管理(符号表),便于查问题。

使用枚举:解决const 变量需要定义问题

使用内联:解决++a等隐藏错误。

2.1.3.条款3 尽可能使用const

使用原因:将某些东西声明为 const 有助于编译器发现使用错误。

可用于:全局变量/static变量、局部变量、指针、成员变量this指针、函数返回值。

指针为例:const出现在星号左边,表示被指物是常量,const出现在星号右边,表示指针本身是常量;const出现在左右两边,表示被指物和指针都是常量。

1、编译器坚持 bitwise constness(二进制位常量性),但是你应该用 conceptual constness(概念上的常量性)来编程。概念上的常量性指的是在程序中,任何在编译时确定且在执行过程中不发生变化的值。如传回&不能定义为const, 改变了指针所指向的内存的内容不能为const。
2、不太重要的,使用mutable (从编译器二进制位常量性解放出来)。
3、当 const 和 non-const member functions(成员函数)具有本质上相同的实现的时候,使用 non-const 版本调用 const 版本可以避免 code duplication(代码重复)。

2.1.4.条款4 确认对象被使用前已先被初始化

原因:读取一个 uninitialized values(未初始化值)会引起 undefined behavior(未定义行为)。
方法:

1、手动初始化 built-in type(内建类型)的non-member objects(非成员对象),其他情况下由构造函数负责。
2、构造函数使用成员初始化列表初始化对象,会调用对象的构造函数,而不是在函数体内赋值。列表排列顺序与在类内声明时一致。基类–对象。
3、使用局部静态对象,代替全局静态对象初始化。解决不同文件初始化顺序不同导致初始化异常问题。

2.2.如何设计类

2.2.1.条款5 c++默默编写并调用的函数管理

1、编译器可以暗自为class创建default构造函数、copy构造函数、copy assignment操作符,以及析构函数。当自己定义了这些函数后,编译器不会再自动创建。
2、若不想使用编译器自动生成的函数,就该明确拒绝,= delete.

1、C++11中,当我们定义一个类的成员函数时,如果后面使用"=delete"去修饰,那么就表示这个函数被定义为deleted,也就意味着这个成员函数不能再被调用,否则就会出错。
2、在C++11之前,当我们希望一个类不能被拷贝,就会把构造函数定义为private,但是在C++11里就不需要这样做了,只需要在构造函数后面加上=delete来修饰下就可以了。

2.2.3.条款7 为多态基类声明virtual析构

1、Polymorphic(带多态性质的) base class应该声明一个virtual析构函数。如果class带有任何virtual函数,他就应该拥有一个virtual析构函数。
2、Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不应该声明virtual析构函数。

virtual具有继承性:父类中定义为virtual的函数在子类中重写的函数也自动成为虚函数。
使用场景:第一,修饰父类中的函数 ;第二,修饰继承性(菱形继承)。

override关键字作用:如果派生类在虚函数声明时使用了override描述符,那么该函数必须正确重载其基类中的同名函数,否则代码将无法通过编译。增加了检查性。能加override就加。

操作符重载可以为虚函数。

条款8 别让异常逃离析构函数

1、析构函数绝对不要吐出异常,如果一个析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序。如果吐出异常,大量对象析构造成同一时间大量异常,程序结束或不明确的行为。
2、如果 class(类)客户需要能对一个操作抛出的 exceptions(异常)做出回应,则那个 class(类)应该提供一个常规的函数(也就是说,non-destructor(非析构函数))来完成这个操作。

2.2.5.条款9 绝不在构造和析构过程中调用virtual函数

原因:此时调用的是基类的虚函数,不会调用派生类的。

2.2.3-1 C++构造、析构执行顺序:

1、基类构造函数,按照它们被继承的顺序构造。
2、成员对象的构造函数按照它们声明的顺序构造。因为构造函数中可以使用这个对象中的成员变量,所以调用构造函数的时候,成员变量需要初始化好。
3、类自己的构造函数。
注意:构造函数的执行顺序与初始化列表中的申明顺序无关。初始化列表可以标记是调用哪个构造函数。

析构顺序,是构造顺序的逆:(后创建的可能依赖于前面创建的)
(1)先调用析构函数,再析构类中的成员变量
(2)成员变量的析构顺序与变量在类中声明的顺序是相反的。

2.2.6.条款10 令operator=返回一个引用 to *this

目标:支持连续赋值,如a=b=c。
1、请记住:令赋值(assignment)操作符返回一个regerence to this。并且确保当对象自我赋值时operator=有良好行为。
原因如下:T&,返回引用可以提高返回的效率。

a = b; 不是引用时,会多调用一次copy构造函数而已。

2.2.7.条款11: 在 operator= 中处理 assignment to self(自赋值)

1、当一个 object(对象)被赋值给自己的时候,确保 operator= 是行为良好的。技巧包括比较 source(源)和 target objects(目标对象)的地址,关注语句顺序,和 copy-and-swap。

Date& operator=(const Date& d)
{
   
	if (this != &d
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值