从构造函数或析构函数进行虚拟调用¶
ID: cpp/virtual-call-in-constructor
Kind: problem
Security severity:
Severity: warning
Precision: high
Tags:
- reliability
- readability
- language-features
- external/jsf
Query suites:
- cpp-security-and-quality.qls
此规则查找从构造函数或析构函数对虚拟函数的调用,这些调用可能会解析为与预期不同的函数。在实例化派生类时,虚拟函数调用的解析取决于定义*当前正在运行*的构造函数/析构函数的类型,而不是正在实例化的类。这是为了防止调用派生类中依赖于派生类中声明的字段的函数。在调用派生类的构造函数(*在*基类的构造函数*之后*)之前,此类字段的值未定义。同样,在调用基类的析构函数*之前*,将销毁派生类中声明的值。
指示的函数调用是对构造函数或析构函数中虚拟函数的调用,这很可能不会调用预期的函数,或者即使调用正确,如果没有类的继承图的知识也很难解释。
建议¶
不要从构造函数或析构函数调用虚拟函数。将基类中的虚拟函数更改为非虚拟函数,并从派生类传递任何必需的参数,或者在构造之后/销毁之前执行需要虚拟函数的初始化。
示例¶
class Base {
protected:
Resource* resource;
public:
virtual void init() {
resource = createResource();
}
virtual void release() {
freeResource(resource);
}
};
class Derived: public Base {
virtual void init() {
resource = createResourceV2();
}
virtual void release() {
freeResourceV2(resource);
}
};
Base::Base() {
this->init();
}
Base::~Base() {
this->release();
}
int f() {
// this will call Base::Base() and then Derived::Derived(), but this->init()
// inBase::Base() will resolve to Base::init(), not Derived::init()
// The reason for this is that when Base::Base is called, the object being
// created is still of type Base (including the vtable)
Derived* d = new Derived();
}
参考文献¶
AV 规则 71.1,*联合攻击战斗机航空器 C++ 编码标准*。洛克希德·马丁公司,2005 年。
S. Meyers。*Effective C++ 第三版*。第 48-52 页。Addison-Wesley Professional,2005 年。