条款01
视C++为一个语言联邦
条款02
尽量以const,enum,inline替换#define
宁可以编译器替换预处理器
1.
#define ASPECT_RATIO 1.653
//采用上述方法时,若在编译过程中发生错误,错误信息将提及1.653而不会提及ASPECT_RATIO
const double AspectRatio = 1.653
//采用该方法时,错误信息中就会提及AspectRatio
2.
//若要在头文件内定义一个常量的char*类型字符串:
const char* const authorName = "Scott Meyers"
//前一个const限制字符串,后一个const限制指针
3.
//#define不重视作用域
class CostEstimate
{
private:
static const double FudgeFactor;
...
};
const double CostEstimate::FudgeFactor = 1.35;
4.
//the enum hack补偿做法
class GamePlayer
{
private:
enum{NumTurns = 5};
int scores[NumTurns];
}
条款03
尽可能使用const
1.
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
2.
//const成员函数
class TextBlock
{
public:
...
const char& operator[](std::size_t position)const //operator[] for const对象
{
return text[position];
}
char& operator[](size::size_t position)
{
return text[position];
}
private:
std::string test;
}
//例子
TextBlock tb("hello");
const TextBlock ctb("world");
//
ctb[0] = 'x' //错误
3.
//const对象无法访问非const部分,解决方法mutable关键字
class CTextBlock
{
public:
...
mutable int textLength;
}
...
const CTextBlock sample;
sample.textLength = 10 //在加mutable下成功
4.
const char& operator[](param)const
{
...
}
char& operator[](param)
{
...
}
//上述造成大量代码重复
//下为解决方法
const char& operator[](param)
{
...
}
char& operator[](param)
{
return
const_cast<char&>
static_cast<const TextBlock&>(*this)[position];
}
条款04
确定对象被使用前已经初始化
1.
//一种初始化方法,效率更高
class ABEntry
{
public:
int a,b;
ABEntry(int x,int y):a(x),b(y)
{}
}
2.
//确保初始化的一种方法
class FileSystem
{
public:
...
std::size_t numDisks() const;
}
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
class Diretory
{
public:
Directory(param)
{
something = tfs().something;
}
...
}
条款05
了解C++默默编写并调用哪些函数
1.
class Empty
{
//编译器自动添加:
Empty(){...}
Empty(const Empty& rhs){...}
~Empty(){...}
Empty& operator=(const Empty& rhs){...}
}
2.
class NameObject
{
public:
string& nameValue;
const int objValue;
NameObject(string& name,int obj){...} //赋值给上述变量
}
...
NameObject a("i am a",1);
NameObject b("i am b",2);
a = b; //拒绝编译引用和常量的赋值,因为不合法
条款06
若不想使用编译器自动生成的函数,明确拒绝
1.
//一下类无法使用=号赋值,也无默认赋值构造函数
class Home
{
private:
Home(const Home&);
Home& operator=(const Home);
...
}
2.
class Uncopyable
{
protect:
Uncopyable(){}
~Uncopyable(){}
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
class Home:private Uncopyable{...};
条款07
为多态基类声明virtual析构函数
1.
class Time
{
public:
Time();
virtual ~Time();
}
...
class Atom : public Time
{
public:
~Atom(){...}
}
...
Time * a = new Atom;
delete a;//以Time的类身份删除
//若此时Time析构函数Atom的析构函数
条款08
别让异常逃离析构函数
1.
//场上同时存在两个异常时,结果不可预测
class Widget
{
public:
...
~Widget(){...} //假设可抛出异常
}
void doSomething()
{
vector<Widget> v;
...
}
//doSomething销毁时可能出现两个异常
2.
class DBConnection
{
public:
...
static DBConnection create();
void close();
}
class DBConn
{
public:
...
~DBConn()
{
db.close();
}
private:
DBConnection db;
}
...
{
DBConn dbc(DBConnection::create());
...
}
...
DBConn::~DBConn()
{
try{db.close();}
catch{...} //两种方法,吞下异常,记录异常
}
条款09
绝不在构造和析构过程中调用virtual函数
class Transaction
{
public:
Transaction()
{
...
log();
}
virtual void log()const = 0;
}
...
class Buy: public Transaction
{
public:
virtual void log()const;
}
...
Buy b;
//当创建b时先调用Transaction的构造函数,但是Transaction的构造函数里的log是调用的Transaction的log
//此时的virtual不具有virtual性质
条款10
令operator=返回一个reference to * this
class Widget
{
public:
...
}
...
Widget& operator=(const Widget& rhs)
{
...
return *this;
}
条款11
在operator=中处理自我赋值
class Widget {...}
Widget w;
...
w = w;
//
class Bitmap{...}
class Widget
{
...
private:
Bitmap* pb;
}
...
Widget&
Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
//以上例子若发生自我赋值(w=w),则delete时将把两个地方的pb都删除
//解决方法
{
...
if(this == &rhs) return *this; //加一个判断条件
}
//以上方案并不绝对安全
//解决方法2
Widget& Widget::operator=(const Widget& rhs)
{
Bitmap* pOrig = pb;
pb = new Bitmap(*rhs,pb);
delete pOrig;
return *this;
}
//以上方法保证在删除前创建完新的对象
//解决方法3
class Widget
{
...
void swap(Widget& rhs); //交换this与rhs的数据
...
};
...
Widget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
}
条款12
复制对象时勿忘其每一个部分