TAG / c++

严重避免在构造/析构过程中调用虚函数

之前只知道在 C++ 的构造器中,调用虚函数(非纯虚函数)不会出现多态的情况,却想当然认为既然析构器可以被声明为虚“函数”,那么析构器应该是能实现虚函数调用的的多态结果的。
事实证明,我又被蒙骗了!

构造器/析构器不会在调用虚函数时执行子类的重载实现,而且更危险的是当构造器/析构器“间接地”调用了虚函数(例如调用了一个非虚函数,但这个函数里调用了虚函数),不仅子类的重载实现不会被执行,而且还很难发现这种 bug。

所以,切记,切忌在构造器/析构器中直接或间接地调用任何虚函数!(单是在构造器/析构器中直接或间接地调用其他对象的虚函数并不受影响)


#ifdef 中的逻辑与或操作

原本用宏定义包起来的代码类似如下:

#ifndef A
// codes
#endif // A

现在要加入一个宏定义 B,实现类似这样的条件判断(显然实际上这样是不行的):

#ifndef A && ifdef B

其实应该这样:

#if (!defined A) && (defined B)
// codes
#endif // !A && B

这就修正了之前一直以为的“既生 #ifdef,何生 #if defined”的思维,其实还是有差别的


用 前置声明,还是用 #include?

为了能让编译速度快一点,明智之举是使用前置声明,而不是 #include 整个头文件。

那声明时候可以用前置声明,而什么时候必须 #include 头文件呢?简单的说:

  1. 当不需要用到类型的具体实现时,包括构造器赋值运算符成员函数等,只需要前置声明就可以了
  2. 当需要用到类型的以上方法时,就不得不 #include 整个头文件

对该技巧的具体分析可以参考这里这里


(const int * i || int const * i) && int * const i

记了无数遍,终于记清楚了。。

const int * i 和 int const * i:

const 修饰后面的 * i,即 i 所指向的 int 空间内的数值不能被改变,但i的指向可以被改变,例如操作

int j = 1;
const int * i = &j;
*i = 2;

是非法的,但是

int j = 1, k = 2;
int * const i = &j;
i = &k;

是合法的;

int * const i:

cons 修饰后面的 i,即 i 的指向不能被改变,但 i 所指向的 int 空间内的数值可以被改变,和上面的例子正好相反。


Page 2 of 212