条款02用const,enum,inline替换#define
- 对于常量,最好以以const对象或enums替换#defines。
- 对于形似函数的宏(macros),最好改用inline函数替换#defines。
//#define ASPECT_RATIO 1.653 >>
const double AspectRatio = 1.653
class GamePlayer {
private:
static const int NumTurns = 5;
int scores[NumTurns];
};
class GamePlayer {
private:
enum { NumTurns = 5 };
int scores[NumZTurns];
}
//#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b)) >>>
template<typename T>
inline void callWithMax(const T& a, cosnt T& b)
{
f(a > b ? a : b);
}
- 对于单纯常量,最好以const对象或enums替换#defines
- 对于形似函数的宏,最好改用inline函数替换#defines
条款03尽可能使用const
char greeting[] = "hello";
char *p = greeting; //non-const pointer, non-const data
const char* p = greeting; //non-const pointer, const data
char* const p = greeting; //const pointer, non-const data
const char* const p = greeting; //const pointer, const data
const出现在星号左边,表示被指物是常量,如果在星号右边,指针自身是常量。
void f1(const Widget *pw);
void f2(Widget const *pw);
上面两种是一样的方式,都是在星号前面。
class TextBlock{
public:
//...
const char &operator[](std::size_t position) const
{ return text[position]; }
char &operator[](std::size_t position)
{ return text[position]; }
private:
std::string text;
};
const成员函数可以被重载,有了const修饰可以区分哪些函数是改动对象内容,那个函数不是。
条款04初始化列表和构造函数
#include <iostream>
using namespace std;
class CMember {
public:
CMember() {
cout << "CMember constructor 1" << endl;
cmember = 0;
}
CMember(CMember& obj)
{
cout << "CMember copy constructor" << endl;
}
CMember(int _cmember) {
cout << "CMember constructor 2" << endl;
cmember = _cmember;
}
CMember& operator =(CMember& obj)
{
cout << "CMember =" << endl;
return *this;
}
private:
int cmember;
};
class MInConstruct {
public:
MInConstruct(CMember &_cm) {
cm = _cm; //这里其实是赋值,而非初始化
}
CMember cm; //Need initialized
};
class MInInitlist {
public:
MInInitlist(CMember &_cm) : cm(_cm) {
}
CMember cm;
};
int main(int argc, char *argv[])
{
CMember c1(1);
cout << "-------MInConstruct start-------"<< endl;
MInConstruct mc(c1);
cout << "-------vMInInitlist start-------"<< endl;
MInInitlist mi(c1);
}
因为编译器总是确保所有成员对象在构造函数体执行之前初始化,所以类类型的数据成员对象,在进入构造函数体之前已经完成构造。
所以在MInConstruct::MInConstruct(CMember &_cm)中在调用cm前,先调用构造函数,再调用赋值操作符。
而在MInInitlist::MInInitlist(CMember &_cm)中,则直接调用拷贝构造函数。
为了避免对象初始化之前过早的使用,需要做三件事:
- 收工初始化内置型non-member对象
- 使用成员初值列对付对象的所有成分