5

我试图在其继承树中某个类的构造函数中发现对象的最派生类。我现在已经花了几个小时在这上面,我不知道我还能怎么做,或者为什么它没有意义。这似乎很合理,但它拒绝工作。我找到了很多关于 RTTI 的页面,但基本上都没有找到。在我的测试用例及其输出之后,我将继续解释。

来源:

#include <iostream>
#include <typeinfo>
#include <string>

class A
{
public:
  A(std::string foo);

  virtual void bar(A* a) = 0;
};

class B : public A
{
public:
  B();

  virtual void bar(A* a);
};

A::A(std::string foo)
{
  std::cout << "type as passed to A constructor: " << foo << " (" << this << ")" << std::endl;
  std::cout << "type as determined in A constructor: " << typeid(*this).name() << " (" << this << ")" << std::endl;
}

B::B() : A(typeid(*this).name())
{
  A* a = (A*)this;
  std::cout << "type as determined in B constructor: " << typeid(*a).name() << " (" << this << ")" << std::endl;
  this->bar(this);
}

void B::bar(A* a)
{
  std::cout << "type as determined in bar: " << typeid(*a).name() << " (" << a << ")" << std::endl;
}

int main()
{
  B b;
  b.bar(&b);

  return 0;
}

输出(在 g++ 上):

type as passed to A constructor: 1B (0x7fff5fbff910)
type as determined in A constructor: 1A (0x7fff5fbff910)
type as determined in B constructor: 1B (0x7fff5fbff910)
type as determined in bar: 1B (0x7fff5fbff910)
type as determined in bar: 1B (0x7fff5fbff910)

我试图让输出的第二行说“1B”而不是“1A”。出于某种我无法想象的原因,RTTI 是否从“这个”中剥离出来?这怎么不打破虚函数的概念呢?(我已经用虚函数实现了这个,直到我发现我正在重新实现 RTTI 的一部分,这是我以前不知道的。)如输出所示,如果我避免使用“this”,我可以完成这项工作,但需要这样做似乎是设计上的破坏。

4

3 回答 3

4

你不能这样做,因为你误解了所涉及的动态。

规则是:

任何类的thisin 构造函数/析构函数都指向其构造函数/析构函数所在的类。

此外,这也是virtual在构造函数中调用的函数的行为不像您通常期望的virtual函数在使用动态调度时那样工作的原因。

您应该在调用构造函数之后检测类型。您可以在除构造函数和析构函数之外的任何成员函数中执行此操作。

于 2012-06-20T05:49:16.420 回答
3

您正在看到预期的行为。在构造函数的主体中,正在构造的对象的类型与正在执行构造函数的类的类型相同,而不是正在构造的最派生类的类。

typeid(*this)当在成员初始化表达式中使用时,异常确实存在于表达式中。这在 C++03 中曾经是未定义的行为,但在 C++11 中已更改,因此您获取的是构造函数类的类型,而不是尚未构造的实际对象的类型。

于 2012-06-20T05:55:25.953 回答
0

考虑你的继承关系,你应该已经知道 will 的构造函数A首先执行,然后是 will的构造函数B。在 的构造函数中A,对象还不是 a B,因为它还没有被构造。因此,构造函数中对象的动态类型始终是类本身的类型,而不是派生类的类型。同样的情况也发生在析构函数中。

简而言之,你想做的事情不能在施工时完成。

于 2012-06-20T05:49:26.557 回答