假设我有这两个类:
class A {
public:
A() { foo() };
protected:
virtual void foo();
};
class B : public A {
public:
B() : super();
private:
typedef A super;
void foo();
};
如果我创建一个对象B,有没有办法强制A的构造函数在调用它时使用overriden方法?
答案 0 :(得分:2)
没有。事实并非如此。 根据Effective c ++,当对象初始化时,虚函数不起作用。 (我用手机写的所以这里可能是错别字)
最好的问候。
答案 1 :(得分:1)
C ++标准,第12.7节[构造和销毁]:
可以调用成员函数,包括虚函数(10.3) 在建造或毁坏期间(12.6.2)。当虚拟功能是 直接或间接地从构造函数或析构函数调用, 包括在建造或破坏班级期间 非静态数据成员以及调用适用的对象 正在构建或销毁的对象(称之为x),该函数 被调用的是构造函数或析构函数类中的最终覆盖,而不是在更派生的类中覆盖它
如果您在A
构造函数中,此时您的对象为A
,则调用是否来自B
构造函数无关紧要。
因此始终会调用A::foo
。
答案 2 :(得分:0)
从A
调用B
构造函数时,B
尚未构建,因此不会虚拟调用A::foo
。
您可以创建一个函数来创建和初始化您的对象:
struct Base
{
virtual ~Base();
virtual void init();
};
struct D : Base
{
void init() override;
};
D make_D()
{
D d;
d.init();
return d;
}
答案 3 :(得分:0)
使用虚拟表解析对虚拟功能的调用。具有至少一个虚函数(及其所有派生类)的任何类都将具有虚拟表(在本例中为A和B),并且该虚拟表将按照它们的顺序包含所有虚函数的地址。声明。当创建任何此类的对象时,该对象包含指向虚拟表的隐藏指针vptr。因此,首先使用vptr转到虚拟表,然后添加被调用函数的偏移量以获取函数的地址,然后使用此地址调用函数,从而解决虚函数调用。现在重要的是,vptr在类的构造函数中初始化,在特定的构造函数中,它将指向该特定类的虚拟表。在这种情况下,当创建B的对象时,A的构造函数中的vptr(首先调用基类构造函数)将指向A的虚拟表,并且当调用B的构造函数时,vptr将仅指向虚拟B.表示在A的构造函数中,vptr指向A的虚拟表。因此,当你调用foo()时,编译器将转到A的虚拟表,获取foo()的地址,在这种情况下是A的foo()并调用此函数。这就是我们通常说虚拟机制在构造函数中不起作用的原因。原因是vptr没有完全初始化,也没有指向派生类最多的vtable。 我希望这会有所帮助。