“this”的dynamic_cast。内部构造函数 [英] dynamic_cast of "this" inside constructor

查看:142
本文介绍了“this”的dynamic_cast。内部构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题与这个问题非常相似为什么动态播放侧向



标题:


$ b在多重继承期间, $ b

  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(){}
};

资料来源:

 code> 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; }

主要:

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

cout<< 再次检查...< endl;
cout<< !! dynamic_cast< A *>(& c)< endl;

return EXIT_SUCCESS;
}

结果:

 打印C ... 
A
B
再次检查...
1
因此,dynamic_cast用于多重继承(没有惊喜!),但为什么不在运行时调用B的this指针: :B()?我认为对象完全形成一次在构造函数体内,即所有的内存被分配给组件对象,它们还没有被初始化。我明白,这取决于超类的构造函数顺序,但在这个例子中A是在B之前调用。



我显然不明白发生了什么,有人请开启我吗?



谢谢,
Cam Bamber。

解决方案>

基本上,标准说它在构造对象期间不会工作(dynamic_cast)。
< quote>



编辑:根据下面的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;

额外的输出将是:

  0 //无法将B转换为A 
1 //可将此B转换为A,因为它实际上是C.
1 //这是我们在B :: B()中执行失败的操作
//它不是dynamic_cast<>失败,但是从C *转换为B *
//导致UB

它在构造函数中失败,因为对象未完全形成。使用这个,我们试图在C构造函数开始之前(由用户定义的代码)将C指针转换为B指针。因此,使用 this 在B :: B()作为指向C对象的指针失败,因此当dynamic_cast <>被调用时,它无法做你想做的因为UB。



12.7建造和销毁[class.cdtor]



第3段


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


[示例:

  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从E *到A *
//可能使用路径E *→D *→A *
//但D不构造
// D((C *)this),
//定义:
// E * →C *定义,因为E()已经开始
//和C *→A *定义,因为
// C完全构造
X(this){// defined: ,
// C / B / D / A子格子完全构造
}
};

- 结束示例]



/ quote>


This question is very similar to this one Why can't I dynamic_cast "sideways" during multiple inheritence?, except that the cast does work - just not inside in the constructor.

Header:

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() {}
};

Source:

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; }

Main:

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;
}

Result:

Printing C...
A
B
Checking again...
1

So, the dynamic_cast does work for multiple inheritance (no surprises there!), but why not when called at runtime for the 'this' pointer inside B::B()? I thought that the object was fully formed once inside the body of the constructor i.e. all the memory was allocated for the component objects, they haven't been initialised yet. I appreciate that this depends on the superclass constructor order, but in this example A is called before B.

I am obviously not understanding what exactly is happening under the hood, can someone please enlighten me?

Thanks, Cam Bamber.

解决方案

Basically the standard says it will not work (dynamic_cast) during construction of an object. <quote>

Edit: Added based on VJo comment below.

Note: The cast from a 'B' to an 'A' using dynamic cast should work because we are casting an object of type 'C'. If we added the following code to 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;

The extra output would be:

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

It fails in the constructor because the object is not fully formed. Using this we are trying to convert a C pointer into a B pointer before the C constructor has started (the code defined by the user). Thus the use of this in B::B() as a pointer to a C object fails thus when the dynamic_cast<> is called on this it fails to do what you want it to because of UB.

12.7 Construction and destruction [class.cdtor]

Paragraph 3

To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.

[ Example:

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
      } 
};

— end example ]

</quote>

这篇关于“this”的dynamic_cast。内部构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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