作者 Scott Meyers 翻译作者 侯捷 C++ 神牛 台湾人
术语:
1.explicit
C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。但他们仍然可以用来进行显示转换。
示例:
class Test1 { public: Test1(int n) { num = n; } //普通构造函数 private: int num; }; class Test2 { public: explicit Test2(int n) { num = n; } //explicit(显式)构造函数 private: int num; }; int main() { Test1 t1 = 12; //隐式调用其构造函数, 成功 Test2 t2 = 12; //编译错误,不能隐式调用其构造函数 Test2 t3(12); //显式调用成功 return 0; }
2 undefined behavior
int *p=0; //p其实是一个NULL指针 std::cout<<*p;//对一个NULL指针取值会导致不明确行为。
条款一:
封装 encapsulation、继承 inheritance、多态 polymorphism
在STL中,迭代器和函数对象都是在C指针之上塑造的,所以对STL的迭代器和函数对象而言,旧式的pass-by-value守则再次适用。
C++高效编程守则视状况而变化,取决于你适用C++的那一部分。 C、Object-Oriented C++、Template C++、STL
条款二:
scope 作用域
enum hock 一个属于枚举类型的数值可权充ints被适用。//权充 (暂且充当)
取一个const的地址是合法的,但取一个enum的地址不合法。
class GamePlayer { private: enum {NumTurns=5}; int scores[NumTurns]; ..... };
宏的不可思议:
1 #include<iostream> 2 3 #define call(a,b) (a)>(b)?(a):(b) 4 int main() 5 { 6 7 int lv1=5,rv1=0; 8 int lv2=5,rv2=0; 9 int result1=call(++lv1,rv1); //lv1累加2次为7 10 int result2=call(++lv2,rv2+10); //lv2累加1次为6 11 std::cout<<result1<<" "<<lv1<<std::endl; 12 std::cout<<result2<<" "<<lv2<<std::endl; 13 system("pause"); 14 15 return 0; 16 }
条款三:
1.STL中iterator的const用法:
std::vector<int> vec; ... const std::vector<int>::iterator iter=vec.begin();//iter 的作用像个T* const *iter=10; //没问题,改变iter所指物 ++iter; //错误! iter是const std::vector<int>::const_iterator cIter=vec.begin(); //cIter的作用像个const *T *cIter=10; //错误! *cIter是const ++cIter; //没问题,改变cIter
2.const成员函数不可以更改对象内任何non-static成员变量。
3.利用C++的一个与const相关的摆动场:mutable(可变的)释放掉non-static成员变量的bitwise constness约束。
mutable bool lengthIsValid; CTextBlock::length() const//这些成员变量可能总是会被更改,即使在const成员函数内。 { lengthIsValid=false; }
4.const_cast: 通常被用来将对象的常量性转除。也是唯一有此能力的C++-style转型操作符。
static_cast:用来强迫隐式转换(implicit conversions),如将non-const对象转为const对象,或者int转为double。
条款四:确定对象被使用前已先被初始化
1.构造函数最好使用成员初始化而不要在构造函数本体内使用赋值操作,初始值列列出的成员变量,其排序次序应该和他们在class类中的声明次序相同。
2.base classess 更早于其derived classes被初始化,而class的成员变量总是以其声明次序被初始化。
ABEntry::ABEntry(const std::string &name,const std::string &address,const std::list<PhoneNumber> &phones)
{
theName=name; //这些都是赋值(assignment)而非初始化(initialization)
theAddress=address; //这会导致首先调用default构造函数为theName,theAddress,thePhones设初值,然后立刻再对它们赋予新值
thePhones=phones; //default构造函数的一切作为被浪费了
numTimeConsulted=0;
}
ABEntry::ABEntry(const std::string &name,const std::string &address,const std::list<PhoneNumber> &phones)
:theName(name),theAddress(address),thePhones(phones),numTimeConsulted(0);
{
//这些都是初始化(initialization)而非赋值(assignment)
}
条款五:了解C++摸摸编写并调用那些函数
一般不能对内含reference成员或者内含const的classes支持赋值操作。如果你要这么做的话就必须要自己定义copy assignment 操作符。
条款六: 若不想使用编译器自动生成的函数,就该明确拒绝
例如如果不需要拷贝构造函数和copy assignment 操作符时,一旦有人调用他们时却会自动默认构造出来。所以只能将函数声明为private而且故意不实现他们。
class HomeForSale
{
public:
...
private:
HomeForSale(const HomeForSale &); //只有声明
HomeForSale & operator=(const HomeForSale &);//没有实现
}
条款七:为多态基类声明vitrual析构函数
1.任何class只要有virtual函数几乎确定应该也有一个virtual析构函数。如果一个class中不含virtual函数,通常表示它并不意图被用做一个base class.而当class不企图被当作base class,令其析构函数为virtual 往往是个馊主意。
2.只有当class内含至少一个virtual函数才为它声明virtual析构函数。
3.polymorphic(带多态性质)base class应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。
4.Classes的设计目的如果不是作为base class使用,或不是为了具备多态性就不该声明virtual析构函数。
来源:https://www.cnblogs.com/xxiaoye/p/3573164.html