|
|
1
185
从构造函数或析构函数调用虚拟函数是危险的,应该尽可能避免。所有C++实现都应该调用在当前构造函数中层次结构定义的函数的版本,而不再调用。 这个 C++ FAQ Lite 在第23.7节中详细介绍了这一点。我建议阅读这篇文章(以及其他常见问题解答),以便后续跟进。 Excerpt:
编辑 最正确的(谢谢李特) |
|
|
2
78
在大多数OO语言中,从构造函数调用多态函数是一个灾难的秘诀。当遇到这种情况时,不同的语言将执行不同的操作。 基本问题是,在所有语言中,必须在派生类型之前构造基类型。现在,问题是从构造函数调用多态方法意味着什么。你希望它表现得怎么样?有两种方法:在基类(C++风格)调用方法,或者调用层次结构底部的未构造对象(Java方式)的多态方法。 在C++中,基类将在进入自己的构造之前构建其虚拟方法表的版本。此时,对虚拟方法的调用将最终调用该方法的基本版本或生成 纯虚拟方法调用 如果它在层次结构的那个级别上没有实现。在基完全构建之后,编译器将开始构建派生类,并且它将重写方法指针以指向层次结构的下一级中的实现。
在Java中,编译器将在构建第一个步骤之前构建虚拟表,在进入基构造函数或派生构造函数之前。含义是不同的(对我来说更危险)。如果基类构造函数调用了在派生类中重写的方法,则实际将在派生级别处理调用,并对未构造的对象调用方法,从而产生意外的结果。在构造函数块内初始化的派生类的所有属性尚未初始化,包括“final”属性。具有在类级别定义的默认值的元素将具有该值。
如你所见,调用多态性( 事实上的 在C++术语中,方法是常见的错误来源。在C++中,至少你有保证它永远不会调用一个尚未构建的对象的方法… |
|
|
3
53
原因是C++对象是像洋葱一样从内向外构造的。在派生类之前构造超级类。所以,在制造B之前,必须先制造A。当A的构造函数被调用时,它还不是B,所以虚函数表仍然有一个条目来获取FN()的副本。 |
|
4
22
这个 C++ FAQ Lite 很好地涵盖了这一点:
|
|
|
5
13
解决问题的一个方法是使用工厂方法创建对象。
class Object
{
public:
virtual void afterConstruction() {}
// ...
};
template< class C >
C* factoryNew()
{
C* pObject = new C();
pObject->afterConstruction();
return pObject;
}
class MyClass : public Object
{
public:
virtual void afterConstruction()
{
// do something.
}
// ...
};
MyClass* pMyObject = factoryNew();
|
|
|
6
1
你知道Windows资源管理器的崩溃错误吗?!
“纯虚拟函数调用…”
因为函数pureVitualFunction()没有实现,并且函数是在构造函数中调用的,所以程序将崩溃。 |
|
|
7
1
vtables由编译器创建。 类对象有指向其vtable的指针。当它启动时,vtable指针指向vtable 基本类的。在构造函数代码的末尾,编译器生成代码来重新指向vtable指针。 到类的实际vtable。这确保调用虚拟函数的构造函数代码调用 这些函数的基类实现,而不是类中的重写。 |
|
8
1
这个 C++ Standard (ISO/IEC 14882-2014) 赛义德:
所以,不要调用
因此,试图从正在构造的基类调用派生类函数是危险的。类似地,对象在构造过程中按相反的顺序被破坏,因此试图从析构函数调用更派生类中的函数可能会访问已释放的资源。 |
|
|
9
1
其他答案已经解释了为什么
通过向基类型添加模板构造函数,这样模板参数总是被推断为派生类型,就可以知道派生类型的具体类型。从那里,你可以打电话
此解决方案不允许-
下面是一个示例实现:
此示例应打印
当A
|
|
|
10
0
首先,创建对象,然后将其地址分配给指针。在创建对象时调用构造函数,并用于初始化数据成员的值。对象指针在对象创建后进入场景。这就是为什么,C++不允许我们将构造函数设为虚拟的。 。另一个原因是,没有什么比指向构造函数的指针更能指向虚拟构造函数,因为虚拟函数的一个属性是它只能由指针使用。
|
|
|
11
0
正如已经指出的,对象是在构建的基础上创建的。在构造基对象时,派生对象尚不存在,因此虚拟函数重写无法工作。 然而,这可以用使用 静态多态性 如果getter返回常量,或者可以用静态成员函数表示,则不使用虚函数,而是使用crtp( https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern )
通过使用静态多态性,基类知道在编译时提供信息时要调用哪个类的getter。 |
|
|
12
-3
我没有看到虚拟关键字的重要性。B是一个静态类型变量,其类型由编译器在编译时确定。函数调用不会引用vtable。构造B时,调用其父类的构造函数,这就是为什么_n的值设置为1的原因。 |
|
|
13
-4
在对象的构造函数调用期间,虚拟函数指针表没有完全生成。这样做通常不会给你期望的行为。在这种情况下调用虚拟函数可能会起作用,但不能保证,并且应避免便携且遵循C++标准。 |