内部构造函数中的"this"的dynamic_cast

cma*_*t85 6 c++ constructor dynamic-cast this multiple-inheritance

这个问题与这个问题非常相似为什么我不能在多重继承期间"动态地"广播"侧身"?,除了强制转换确实有效 - 只是不在构造函数内部.

标题:

class A  
{  
public:  
    virtual                ~A() {}
    void                    printA();
};

class B
{
public:
                            B();
    virtual                ~B() {}
    void                    printB();

private:
    std::string             message_;
};

class C : public A, public B
{
public:
                        C() {}
    virtual                ~C() {}
};
Run Code Online (Sandbox Code Playgroud)

资源:

void A::printA() { cout << "A" << endl; }
B::B()
{
    A* a = dynamic_cast< A* >( this );
    if ( a ) {
        message_ = std::string( "A and B" );
    } else {
        message_ = std::string( "B" );
    }
}
void B::printB() { cout << message_.c_str() << endl; }
Run Code Online (Sandbox Code Playgroud)

主要:

int main( int argc, char* argv[] )
{
    cout << "Printing C..." << endl;
    C c;
    c.printA();
    c.printB();

    cout << "Checking again..." << endl;
    cout << !!dynamic_cast< A* >( &c ) << endl;

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

结果:

Printing C...
A
B
Checking again...
1
Run Code Online (Sandbox Code Playgroud)

因此,dynamic_cast确实适用于多重继承(没有意外!),但为什么不在运行时调用B :: B()中的'this'指针?我认为对象在构造函数体内完全形成,即所有内存都是为组件对象分配的,它们尚未初始化.我理解这取决于超类构造函数的顺序,但是在这个例子中,A在B之前被调用.

我显然不明白究竟发生了什么事情,有人可以赐教吗?

谢谢,Cam Bamber.

Mar*_*ork 7

基本上标准说它在构造对象期间不起作用(dynamic_cast).<报价>

编辑:根据下面的VJo评论添加.

注意:使用动态强制转换从'B'到'A'的转换应该有效,因为我们正在转换类型为'C'的对象.如果我们将以下代码添加到main:

B  bObj;
B& bRef = c;
B* bPtr = &c;
std::cout << !!dynamic_cast<A*>(&bObj) << std::endl;
std::cout << !!dynamic_cast<A*>(&bRef) << std::endl;
std::cout << !!dynamic_cast<A*>( bPtr) << std::endl;
Run Code Online (Sandbox Code Playgroud)

额外的输出是:

0   // Can not convert a B to an A
1   // Can convert this B to an A because it is really a C.
1   // This is  what we are reeling doing in B::B() that fails
    // It is not the dynamic_cast<> that fails but the conversion of this from C* to B*
    // That is causing UB
Run Code Online (Sandbox Code Playgroud)

它在构造函数中失败,因为该对象未完全形成.使用这个,我们试图在C构造函数启动之前将C指针转换为B指针(用户定义的代码).因此,使用thisB :: B()作为指向C对象的指针会失败,因此当调用dynamic_cast <>时,由于UB而无法按照您的意愿执行操作.

12.7建设和销毁[class.cdtor]

第3段

显式或隐式地将引用类X的对象的指针(glvalue)转换为指向X的直接或间接基类B的指针(引用),构造X及其所有直接或间接基础的构造直接或间接从B派生的应该已经开始并且这些类的销毁不应该完成,否则转换会导致不确定的行为.要形成指向对象obj的直接非静态成员(或访问其值)的指针,obj的构造应该已经开始并且它的销毁不应该完成,否则计算指针值(或访问成员) value)导致未定义的行为.

[例如:

struct A { };
struct B : virtual A { };
struct C : B { };
struct D : virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X 
{ 
    E() : D(this),  // undefined: upcast from E* to A*
                    // might use path E* ? D* ? A* 
                    // but D is not constructed 
                    // D((C*)this), 
                    // defined: 
                    // E* ? C* defined because E() has started 
                    // and C* ? A* defined because
                    // C fully constructed 
      X(this) { // defined: upon construction of X,
                    // C/B/D/A sublattice is fully constructed
      } 
};
Run Code Online (Sandbox Code Playgroud)

- 结束例子]

</报价>