|
最近在温习这本经典的Effective C++,好记性不如烂笔头,记录要点,如有不正确之处,欢迎批评指正。
第二章笔记链接:《Effective C++》第二章笔记 构造/析构/赋值运算
第三章笔记链接:《Effective C++》第三章笔记 资源管理
第四章笔记链接:《Effective C++》第四章笔记 设计与声明 [待更新]
第五章笔记链接:《Effective C++》第五章笔记 实现 [待更新]
第六章笔记链接:《Effective C++》第六章笔记 继承与面向对象 [待更新]
第七章笔记链接:《Effective C++》第七章笔记 模板与泛型编程 [待更新]
第八章笔记链接:《Effective C++》第八章笔记 定制new和delete [待更新]
<hr/>条款1:视C++为一个语言联邦
视C++为一个由语言组成的联邦而非单一语言,其由四个部分组成:
- C。C++是C的超集,C是C++的子集。C不包含模板、异常、重载...
- 面向对象C++。继承、封装、多态、virtual等等
- template C++。模板是C++泛型编程的部分
- STL。STL有统一的接口和紧密联系的模块,包括容器、迭代器、算法和函数对象
C++是由这四个次语言组成的联邦,C++高效编程守则视状况而变化,取决你使用C++的哪一部分。
条款2:尽量以const,enum,inline替换#define
比如使用宏:
#define PI 3.14
记号PI或许从未被编译器看见,也许它被预处理器就移走了,于是PI可能被进入记号表内(symbol table),当出现编译错误时,可能报错3.14而不是PI,这会导致难以定位问题。
解决方法:用一个const修饰的常量替换
const double PI = 3.14;再举个例子,用宏实现的替换可能带来问题
CALL_WITH_MAX使用a、b里面的较大值来调用f(a)或者f(b),就算给所有的参数都加上了小括号都有问题
#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))int a = 5,b=0;
CALL_WITH_MAX(++a, b);// 调用一次 ++a
CALL_WITH_MAX(++a, b+10);// 调用两次 ++a
会出现参数不同,a递增次数不同的问题,这显然不是想看到的
条款3:尽可能用const
const会告诉编译器和其他程序员某值应该保持不变,编译器会帮助你,防止值被意外修改,确保这条约束不被违反,提高程序健壮性。
const分为修饰变量、修饰函数类型两种用法
情况1:const修饰变量
1.1 修饰普通类型
当const修饰变量,举个例子,const int a = 10;和int const a = 10;没有区别,两种写法意义相同。
1.2 修饰指针
当const修饰指针比较绕,但细想也不难,记住 const紧邻指针才表示指针不可变
char str[] = &#34;Hello&#34;;
const char* p = str; // 指针指向的元素不可变,指针地址可变
char* const p = str; // 指针指向的元素可变,指针地址不可变
const char* const p = str; // 指针指向的元素不可变,指针地址也不可变
情况2:const修饰函数
2.1 const放在函数名前
当const修饰函数,出现在函数名前,代表修饰的是返回值
2.2 const放在函数名后
当const修饰函数,出现在函数名后,代表函数不能修改对象内任何成员,只能读,函数是read-only的
void MyClass::Func() const {
// 这里无法修改 a 的值 编译错误
std::cout << a << std::endl;
}条款4:确定对象使用前被初始化
- 为内置型对象手动初始化,因为C++不保证初始化它们
- 构造函数最好用成员初始列(排列顺序和在class里声明次序相同),而不是在构造函数里面使用赋值操作。
ABEntry::ABEntry(const std::string& name_, const std::string& address_,
const std::list<PhoneNumber>& phones_)
:name(name_),
address(address_),
phones(phones_){}
第二章笔记链接:
bbtt:《Effective C++》第二章笔记 构造/析构/赋值运算 |
|