在构造函数中使用object-expression调用虚函数 [英] Call a virtual function inside the constructor using an object-expression

查看:129
本文介绍了在构造函数中使用object-expression调用虚函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码:

#include <iostream>

using std::cout;
using std::endl;

struct A
{
    virtual void foo()
    {
        cout << "A" << endl;
    }

    A(){ }
};

struct B : A
{
    B();
    virtual void foo()
    {
        cout << "B" << endl;
    }
};

B b;

B::B()
{
    b.foo();
    foo();
}  

struct C : B
{
    virtual void foo()
    {
        cout << "C" << endl;
    }

    C() : B(){ }      
};

C c;

int main(){ }

DEMO


直接调用虚拟函数或间接从
构造函数或从析构函数,包括在构造期间或
销毁类的非静态数据成员,并且对象
对象(调用它x)

下构造或销毁,调用的函数是最终的
overrider在构造函数或析构函数的类中,而不是一个
重写它在更多派生类。如果虚函数调用
使用显式类成员访问(5.2.5),并且对象
表达式指的是x
的完整对象或
之一对象的基类的子对象,但不是其基类的一个
子对象,行为是未定义的。

When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

尝试接收UB


如果虚函数调用使用显式类成员访问
(5.2.5)对象表达式是指完整的对象x
[...]

If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete object of x [...]

x 对象,其中 x 是一个对象。是否与 x 类型的完整对象相同?

It is unclear what means complete object of x, where x is an object. Is it the same as complete object of type of x?

推荐答案

§1.8[intro.object] / p2-3:

§1.8 [intro.object]/p2-3:


对象可以包含其他对象,称为子对象。子对象
可以是成员子对象(9.2),基类子对象(子句
10)或数组元素。不是任何
其他对象的子对象的对象称为完成对象

Objects can contain other objects, called subobjects. A subobject can be a member subobject (9.2), a base class subobject (Clause 10), or an array element. An object that is not a subobject of any other object is called a complete object.

对于每个对象 x ,有一些对象称为完成对象
x
,确定如下:

For every object x, there is some object called the complete object of x, determined as follows:


  • 如果 x 是一个完整的对象,则 x c

  • 否则,的完整对象 x 是包含 x 的(唯一)对象的完整对象。

  • If x is a complete object, then x is the complete object of x.
  • Otherwise, the complete object of x is the complete object of the (unique) object that contains x.

实质上,你引用的句子使得 static_cast< C *>(this) - > foo(); in B 的构造函数未定义的行为,即使正在构造的完整对象是 C 。标准实际上提供了一个很好的例子:

In essence, the sentence you cited makes doing static_cast<C*>(this)->foo(); in B's constructor undefined behavior in your code, even if the complete object being constructed is a C. The standard actually provides a pretty good example here:

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
}

可以已经看到此示例中显示的未定义的行为,如果您运行它:Ideone的编译器(GCC)实际调用 V :: f() a-> f(); 行,即使指针指的是完全构造的 A 子对象。

In fact, you can already see the undefined behavior show up in this example if you run it: Ideone's compiler (GCC) actually calls V::f() on the a->f(); line, even though the pointer is referring to a fully constructed A subobject.

这篇关于在构造函数中使用object-expression调用虚函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆