正在调用基方法,而不是从构造函数派生方法
Base method is being called instead of derive method from constructor
我原以为派生方法get()
将从A的构造函数调用。想知道为什么没有发生这种情况?
方法get()
在基类中是虚拟的,因此派生类B
将覆盖此方法。
#include <iostream>
using namespace std;
class A {
protected:
virtual int get() {
cout<<" in A::get "<<endl;
return 0;
}
public:
A() {
get();
}
};
class B : public A {
public:
B():A() {}
protected:
int get() override{
cout<<"in B:get() "<<endl;
return 0;
}
};
int main() {
A *a; a = new B();
return 0;
}
虽然这是可能的,有时也是一个不错的选择,但大多数时候在构造函数中调用虚拟函数是个坏主意。只有当你真正理解这意味着什么的时候,才能这样做。这同样适用于在析构函数中调用虚拟函数。
当构造类B
的实例时,它首先构造一个A
。在此阶段,对象仅被标识为A
的实例,而不是B
的实例。所以在那个时候,对象有一个类为A
的虚拟函数表。这意味着每个虚拟函数调用都将解析为类A
(或超类)的函数;应用相同的规则,就好像只构造CCD_ 10的实例一样。
要获得完整的解释,请阅读当我的基类的构造函数在其this对象上调用虚拟函数时,为什么我的派生类对该虚拟函数的覆盖不被调用?
即使可以在A
的构造函数内调用函数B::get()
(例如:http://ideone.com/sF3411),这将是未定义的行为,因为当执行A
的构造函数时,this
指针还没有指向B
的实例,如果您愿意,它只是"准备中"。链接的代码可能会起作用,但这是一次黑客攻击,暴露了未定义的行为。
除了来自leemes的C++FAQ链接,C++标准阻止它被调用,我将引用该标准。
下面说,虚拟成员函数可以在构造函数/析构函数中调用,但它们的作用是"非虚拟的",这在C++常见问题解答中已经知道了。
可以调用成员函数,包括虚拟函数(10.3)在建造或破坏期间(12.6.2)。当虚拟功能直接或间接从构造函数或从销毁器,包括在建造或销毁类的非静态数据成员,以及调用的对象applies是正在构建或销毁的对象(称之为x),调用的函数是构造函数或中的最后一个重写器析构函数的类,而不是在更派生的类中重写它。如果虚拟函数调用使用显式类成员访问(5.2.5),对象表达式是指x的完整对象或该对象的基类子对象之一,但不是x或其基类子对象,行为是未定义的。
它实际上还说,当从一个指针(指向它自己)调用虚拟函数时,该指针的类型不是它自己的直接基类(在多重继承中),行为是未定义的。
示例(来自标准)
struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f();
};
struct B : virtual V {
virtual void g();
B(V*, A*);
};
struct D : A, B {
virtual void f();
virtual void g();
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
f(); // calls V::f, not A::f
g(); // calls B::g, not D::g
v->g(); // v is base of B, the call is well-defined, calls B::g
a->f(); // undefined behavior, a’s type not a base of B
}
上述规则适用于其他动态绑定内容,包括typeid,这意味着您不能在基构造函数中使用typeid来区分派生类类型。
typeid运算符(5.2.8)可以在构造或destruction(12.6.2)。当在构造函数中使用typeid时(包括非静态的mem初始值设定项或大括号或等号初始值设定值数据成员)或在析构函数中,或在调用(直接或间接)来自构造函数或析构函数,如果typeid的操作数指的是正在构造或销毁时,typeid产生std::typeinfo对象,表示构造函数或析构函数的类。如果typeid的操作数引用正在建造或毁坏的物体以及操作数既不是构造函数或析构函数的类,也不是在其基中,typeid的结果是未定义的。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 初始化具有非默认构造函数的std::数组项的更好方法
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- C++方法是否可以根据传递给构造函数的参数具有不同的返回类型?
- C++:将向量传递到构造函数以创建成员变量的最佳方法?
- 在C++中使用默认构造函数初始化对象的不同方法
- 使用默认构造函数初始化对象的不同方法
- 静态 std::map instatiation 在类的方法中调用构造函数吗?
- 定义类模板构造函数的两种方法之间的区别
- 通过构造函数方法输出的类到类类型转换是 5500 为什么不是 5555
- 用相同的参数声明两个构造函数的最偶像化的方法是什么?
- 构造函数是否有一种现代C++方法来了解其'container'类?
- 使用回调函数从构造函数调用虚拟/派生方法的替代方法?
- 如何构造一个类型特征,可以判断一个类型的私有方法是否可以在另一个类型的构造函数中调用?
- 不为 emplace() 定义构造函数的解决方法
- 有没有一种简单的方法可以在对象向量上调用构造函数?
- 删除复制构造函数的 Intel 13.1.2 中不良C++行为的解决方法
- 方法/构造函数及其返回值
- 目标C类方法==C++构造函数