“this”的dynamic_cast构造函数内部
这个问题与这个问题非常相似为什么我不能dynamic_cast在多重继承期间“横向”?,除了强制转换确实有效 - 只是不在构造函数内部。
头:
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;
}
结果:
Printing C...
A
B
Checking again...
1
因此,dynamic_cast 确实适用于多重继承(这并不奇怪!),但为什么在运行时为 B::B() 内的“this”指针调用时不呢?我认为该对象一旦进入构造函数体内就已完全形成,即所有内存都已分配给组件对象,但它们尚未初始化。我明白这取决于超类构造函数的顺序,但在这个例子中,A 在 B 之前被调用。
我显然不明白幕后到底发生了什么,有人可以启发我吗?
谢谢, 卡姆·班伯.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
基本上,标准说它在对象的构造过程中不起作用(dynamic_cast)。
<引用>
编辑:根据下面的 VJo 评论添加。
注意:使用动态转换从“B”到“A”的转换应该有效,因为我们正在转换类型“C”的对象。如果我们将以下代码添加到 main: ,
额外的输出将是:
由于对象未完全形成,它在构造函数中失败。使用它,我们尝试在 C 构造函数启动(用户定义的代码)之前将 C 指针转换为 B 指针。因此,当dynamic_cast<>在B::B()中使用
this
作为指向C对象的指针时,就会失败。由于 UB 的原因,它无法执行您想要的操作。12.7 构造和销毁[class.cdtor]
第3段
[示例:
-结束示例]
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:
The extra output would be:
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
[ Example:
— end example ]
</quote>
每个基类构造函数都在派生类构造函数之前执行,并且在
B
构造函数期间,对象的动态类型为B
;在您输入C
构造函数之前,它不会变成C
。因此,您无法执行任何需要C
动态类型的操作:您无法交叉转换到任何C
的其他基类,并且如果您调用了虚函数,那么您将不会获得C
提供的任何覆盖。在底层,动态类型(至少在大多数实现中)由对象中的指针(称为“vptr”)确定,该指针指向一些指定类属性的静态数据,包括虚函数表(称为“vtable”)以及
dynamic_cast
和typeid
所需的信息。在每个构造函数之前,都会更新它以指向当前正在构造的类的信息。Each base class constructor is executed before the derived class constructor, and during the
B
constructor, the dynamic type of the object isB
; it does not become aC
until you enter theC
constructor. So you cannot do anything that requires a dynamic type ofC
: you can't cross-cast to any ofC
s other base classes, and if you called a virtual function, then you would not get any overrides provided byC
.Under the hood, the dynamic type is (in most implementations at least) determined by a pointer in the object (known as the "vptr"), which points to some static data specifying properties of the class, including a table of virtual functions (known as the "vtable") and the information needed for
dynamic_cast
andtypeid
. Before each constructor, this is updated to point to the information for the class currently under construction.在构建
A
期间,动态类型无论如何都是A
。这是因为您将在构造派生类之前开始调用派生类的成员函数并访问派生成员变量,这将是 UB 并且非常糟糕。During the construction of
A
then the dynamic type isA
regardless. This is because you would start calling member functions of derived classes and accessing derived member variables before it's been constructed, which would be UB and very bad.由于
B
不是从A
继承(B
是最父类),因此B
的动态类型在其构造函数中是B
。只有当A
和B
父级都构造完成后,才能构造子级C
,从而允许横向dynamic_cast
ing 。Since
B
doesn't inherit fromA
(B
is parent-most class), the dynamic type ofB
during its constructor isB
. Only when both theA
andB
parents are constructed can the childC
be constructed, allowing for sidewaysdynamic_cast
ing.它在 B 内部不起作用,因为 B 不继承自 A
It doesn't work inside B, because B doesn't inherit from A