EC++学习笔记(一) 习惯c++
条款01:c++多范式编程语言
条款02:尽量以 const, enum, inline 替换#define
1. 提供类型安全检查
2. 去除函数调用开销
3. 避免宏的二义性
const double pi = 3.1415926; const std::string authorName("wwwjieo0");
宏函数:所有实参必须加上小括号
#define MAX(x, y) ((x) >= (y) ? (x) : (y)) MAX(++a, b); //a被累加两次
c++ inline函数实现:
template<class T> inline T max(const T& x, const T& y) { return (x >= y ? x : y); }
c语言中的宏仍然是必需品:
#include是必需品,#ifdef和#ifndef扮演 条件编译的角色
条款03:尽可能使用const
const 使编译器实施强制保护
char myname[] = "wwwjieo0"; char* p = myname; //non-const pointer, non-const data const char* p = myname; //non-const pointer, const data char* const p = myname; //const pointer, non-const data const char* const p = myname; //const pointer, const data
STL迭代器的const:
const std::vector<int>::iterator it = vec.begin(); //it为const,永远指向begin std::vector<int>::const_iterator it = vec.begin(); //it可以改变,但*it(即容器元素)不可改变
const 成员函数:
const 成员函数不可以更改对象任何non-static 成员变量
可以利用 const 成员函数实现其non-const 版本
const Widget& func(int x, int y) const; //已经实现 Widget& func(int x, int y) { return const_cast<Widget&>(static_cast<const Widget&>(*this).func(x, y)); }
类中的每个non-static 成员函数都有一个隐藏的this参数(第一个参数),这个this指针指向类的实例对象,并且this指针为const pointer
所以 Widget& func(int x, int y) 实际上是 Widget& func(Widget* const this, int x, int y);
而 const 成员版本 Widget& func(int x, int y) const 实际上是 Widget& func(const Widget * const this, int x, int y);
(const int& x)和 (const int x)是重载函数,并不是重复定义
static_cast 将(*this) 加上 const 特性,因为要调用 const 成员函数
const_cast 将 const 成员函数返回值 const Widget& 去除 const 特性,因为要与函数返回值类型相同
注意:不能用non-const 成员函数去实现相应的 const 版本,因为 non-const 函数可能会改变一些值,这不符合 const 函数的要求
条款04:确定对象被使用前已被初始化
永远在使用对象之前先将它初始化:
内置类型:手工初始化,避免未定义行为带来的随机值
自定义类型:确保每一个构造函数都将对象的每一个成员初始化
class Person{ public: Person(const string& name, const string& address); private: string theName; string theAddress; int theId; }; Person::Person(const string& name, const string& address) { theName = name; theAddress = address; theId = 0; }
c++规定,对象的成员变量的初始化动作发生在进入构造函数的函数体之前
所以上面程序中,构造函数内部并不是初始化,而是赋值操作
真正的初始化动作发生在 default 构造函数(编译器自动生成)自动调用之时
构造函数应该使用 成员初始化列表 替换赋值操作
Person::Person(const string& name, const string& address) :theName(name), theAddress(address), theId(0) { }
这种方法效率更高,没有首先调用 default 构造函数,而是在进入构造函数的函数体之前利用 copy构造函数直接初始化
总结:总是使用成员初始值列表,并且在初值中列出所有成员变量
c++初始化次序:base class 更早于 derived class,class 的成员变量总是以其声明次序被初始化