📜  规则 36 (1)

📅  最后修改于: 2023-12-03 15:27:54.758000             🧑  作者: Mango

规则 36

规则 36是由程序员Steve McConnell提出的,它的完整表述是:“永远不要在一个构造器、析构器或是一个操作符等特殊成员函数中调用虚函数”。这个规则是Object-Oriented编程中非常重要的一条规范。

理解规则36

在C++或Java等高级语言中,虚函数的特性使得程序在运行期间可以根据对象的实际类型动态地调用相应的函数。但是,如果在构造器或析构器中调用虚函数,则会发生错误。

如果在构造函数中调用虚函数,那么由于派生类的成员变量还未初始化,所以调用的虚函数执行时会访问到未初始化的成员变量,导致程序不可预知的结果。同样,如果在析构函数中调用虚函数,那么调用的虚函数执行时会访问到已经释放的成员变量,也会导致程序不可预知的结果。

规则36的应用

如果要在构造函数或析构函数中执行某些操作,可以通过调用非虚函数或者直接在函数中写入相应的代码来实现。如果需要在对象的构造过程中执行某些虚函数,可以使用一个初始化函数,而不是在构造函数中调用虚函数。

在简单情况下,规则36这一原则的遵守可能不是那么重要。然而,在复杂的对象层次结构中,以及程序使用多重继承或模板技术时,未能遵循这一规则会导致许多问题和难以调试的错误。

所以一旦违反了规则36,那么代码的正确性就会面临威胁。因此,程序员需要在编写代码时认真思考和遵循规则36的原则。

代码示例

以下是一个简单的代码示例,违反了规则36:

#include <iostream>
using namespace std;

class Base{
public:
   Base(){ 
      cout<<"Base::Base"<<endl; 
      fun();
   }
   virtual void fun(){ 
      cout<<"Base::fun"<<endl; 
   }
   virtual ~Base(){ 
      cout<<"Base::~Base"<<endl; 
      fun(); 
   }
};

class Derived:public Base{
public:
   Derived(){ 
      cout<<"Derived::Derived"<<endl; 
      fun(); 
   }
   void fun(){ 
      cout<<"Derived::fun"<<endl; 
   }
   ~Derived(){ 
      cout<<"Derived::~Derived"<<endl; 
      fun(); 
   }
};

int main(){
   Derived d;
   return 0;
}

执行结果如下:

Base::Base
Derived::fun
Base::~Base
Derived::fun
Derived::Derived
Derived::fun
Derived::~Derived
Derived::fun

在上面的示例代码中,构造一个Derived的实例时,会调用Derived和Base的构造器,以及它们的fun()函数,再析构Derived对象时也会调用fun().这时候输出结果表明,fun()函数的行为是不按照预期进行的。