【Effective C++】
1、只有int型的class static变量能在类中定义,其它类型(如double)只能在类中声明,在类外定义。
class Student { private: // static int 可以在类中定义 static const int age = 5; }; class GamePlayer { private: // 非int型static变量只能在类中声明 static const double NumTurns; // 下面这行代码会有编译错误 // static const double NumTurns = 1.35f; }; // 在类外定义 const double GamePlayer::NumTurns = 1.35f;
2、能不用宏定义,就尽量不用。如下例,将宏替换为函数,就不会存在此问题。
#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b)) void f(int value) {} int main() { int a = 5, b = 0; CALL_WITH_MAX(++a, b); // a被累加2次 CALL_WITH_MAX(++a, b+10); // a被累加1次 getchar(); return 0; }
3、迭代器的作用就像个T*指针。const ::iterator 类似 T* const,而 ::const_iterator 类似const T*。
std::vector<int> vec; const std::vector<int>::iterator iter = vec.begin(); // iter类似T* const *iter = 10; // 正确,iter指向的是非const //++iter; // 错误,iter本身是const std::vector<int>::const_iterator cIter = vec.begin(); // cIter类似 const T* //*cIter = 10; // 错误,cIter指向的内容是const ++cIter; // 正确,cIter本身是非const
4、operator类重载应当返回一个const变量。否则会产生如下问题。
class Rational {}; const Rational operator * (const Rational& lhs, const Rational &rhs); int main() { Rational a, b, c; // 因为返回值为const Rational,所以下行代码编译错误 // (a*b) = c; getchar(); return 0; }
返回cosnt还可以避免,如下错误:
if (a*b == c) {} // 下面属于手误,少打了一个=,会发生编译错误 //if (a*b = c) {}
5、none-const operator[]应当返回一个none-const reference。否则,下述赋值代码就会失败。
tb[0] = 'x'
6、const函数,必须返回一个const变量。否则会产生如下问题。
class CTextBlock { public: CTextBlock(char*p) { pText = p; } char& operator[] (std::size_t position) const { return pText[position]; } private: char *pText; }; int main() { const CTextBlock cctb("Hello"); char *pc = &cctb[0]; *pc = 'J'; // 现在有了'Jello'这样的数据 getchar(); return 0; }
7、mutable在成员变量可以在const函数内被修改。
8、当const、non-const函数有相同逻辑代码时,用non-const函数调用const函数的实现。
char& operator[] (std::size_t position) { return const_cast<char&>(// 将cosnt属性移除 static_cast<const CTextBlock>(*this)[position] ); }
9、编译器会为类声明构造函数、析构函数、copy构造函数、copy assignment函数。
如果声明了一个构造函数,编译器不再创建default构造函数。
class Empty { public: Empty(){} Empty(const Empty& rhs){} ~Empty(){} Empty& operator=(const Empty& rhs){} };
10、如果你打算在一个“内含reference成员”的class内支持赋值操作(assignment),你必须定义自己的copy assignment函数。此种情况下,编译器不会生为你生成copy assignment函数。
内含const成员也是一样的,编译器拒绝生成copy assignment。
如果基类copy assignment定义为private,则编译器也拒绝为derived class生成copy assignment。
11、把函数设置为private并不安全,因为member function、friend function还是可以访问private。
将函数声明为priavte,而故意不实现它,现是解决方案。
下在也是一种解决方案,但可能存在多重继承问题。
class Uncopyable{ protected: Uncopyable(){} ~Uncopyable(){} private: Uncopyable(const Uncopyable&); Uncopyable& operator =(const Uncopyable&); }; class Entry : private Uncopyable{};
12、每一个带有virtual函数的class都有一个vtable。
13、将拥有non-virtual析构函数的类作为基类是非常愚蠢的。
class SpecialString : public std::string // bad desing, string有个non-virtual destructor { public: SpecialString(); ~SpecialString(); private: };
C++并没有你Java中的final class或C#中的sealed class机制。
14、析构函数绝对不要吐出异常。如果destructor调用的函数可能抛出异常,那么捕获它,吞下它。
15、不要在constructor、destructor中调用virtual函数。因为constructor、destructor中的virtual函数无效。
16、auto_ptr当copy、assignment时,内部指针会变为NULL。
auto_ptr更好的方案是引用计数指针,shared_ptr。引用计数无法打破环状引用。
auto_ptr、shared_ptr调用的都是delete,而非delete[]。如果需要delete[],可以用scoped_array、shared_array。
17、下述代码可能产生异常。
procesWidge(std::tr1::shared_ptr<Widget>(new Widget()), priority());