“this"的dynamic_cast内部构造函数
这个问题与这个问题非常相似为什么可以't I dynamic_cast sideways"在多重继承期间?,除了强制转换确实有效 - 只是不在构造函数内部.
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.
标题:
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() {}
};
来源:
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 << "Printing C..." << endl;
C c;
c.printA();
c.printB();
cout << "Checking again..." << endl;
cout << !!dynamic_cast< A* >( &c ) << endl;
return EXIT_SUCCESS;
}
结果:
Printing C...
A
B
Checking again...
1
因此,dynamic_cast 确实适用于多重继承(这并不奇怪!),但为什么在运行时调用 B::B() 中的this"指针时不这样做呢?我认为该对象在构造函数体内一次完全形成,即所有内存都分配给组件对象,它们尚未初始化.我很欣赏这取决于超类构造函数的顺序,但在这个例子中,A 在 B 之前被调用.
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?
谢谢,卡姆班博.
推荐答案
基本上标准说在构造对象期间它不会工作(dynamic_cast).<引用>
Basically the standard says it will not work (dynamic_cast) during construction of an object. <quote>
根据下面的 VJo 评论添加.
Added based on VJo comment below.
注意:使用动态转换从B"到A"的转换应该可以工作,因为我们正在转换一个类型为C"的对象.如果我们在main中加入如下代码:
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;
额外的输出是:
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
它在构造函数中失败,因为对象没有完全形成.使用它,我们试图在 C 构造函数启动(用户定义的代码)之前将 C 指针转换为 B 指针.因此,在 B::B() 中使用 this
作为指向 C 对象的指针失败,因此当 dynamic_cast<>对此调用它由于 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.
第 3 段
将指向 X 类对象的指针(泛左值)显式或隐式转换为指向 X 的直接或间接基类 B 的指针(引用),X 的构造及其所有直接的构造或直接或间接派生自 B 的间接基类应已开始,并且这些类的销毁尚未完成,否则转换将导致未定义的行为.为了形成一个指向(或访问)对象 obj 的直接非静态成员的指针,obj 的构造应该已经开始并且它的销毁应该没有完成,否则指针值的计算(或访问成员value) 导致未定义的行为.
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.
[ 示例:
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
}
};
――结束示例]
相关文章