【问题标题】:Checking the object type in C++11在 C++11 中检查对象类型
【发布时间】:2013-06-16 18:28:12
【问题描述】:

我有继承自 A 的 B 类。

class A
{
};

class B : public A
{
};

我有三个对象。

A* a = new A();
A* a2 = new B();
B* b = new B();

我想检查a是否是A类型的对象,a2是B类型的对象(不是A),b是B类型的对象。

我尝试了键入比较,但它没有给我正确的答案。

cout << (typeid(*a) == typeid(A)) << endl; // -> 1
cout << (typeid(*a2) == typeid(A)) << endl; // -> 1
cout << (typeid(*b) == typeid(A)) << endl; // -> 0

cout << (typeid(*a) == typeid(B)) << endl; // -> 0
cout << (typeid(*a2) == typeid(B)) << endl; // -> 0
cout << (typeid(*b) == typeid(B)) << endl; // -> 1

我尝试了动态转换,但出现编译错误。

B* derived = dynamic_cast<B*>(a);
if (derived) {
    cout << "a is B";
}
derived = dynamic_cast<B*>(a2);
if (derived) {
    cout << "a2 is B";
}
derived = dynamic_cast<B*>(b);
if (derived) {
    cout << "b is B";
}

typename.cpp: In function 'int main(int, char**)':
typename.cpp:27:36: error: cannot dynamic_cast 'a' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
     B* derived = dynamic_cast<B*>(a);
                                    ^
typename.cpp:31:34: error: cannot dynamic_cast 'a2' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
     derived = dynamic_cast<B*>(a2);

我使用了静态转换,但我得到了错误的答案。

B* derived = static_cast<B*>(a);
if (derived) {
    cout << "a is B"; // -> YES
}
derived = static_cast<B*>(a2);
if (derived) {
    cout << "a2 is B"; // -> YES
}
derived = dynamic_cast<B*>(b);
if (derived) {
    cout << "b is B"; // -> YES
}

如何正确识别C++11中的对象类型?

【问题讨论】:

  • *aA 类型,*b 根据他们的声明是 B 类型。
  • 动态转换仅适用于虚拟,但您的代码没有任何虚拟功能。
  • 类似于您的代码的最佳最小解决方案:coliru.stacked-crooked.com/…

标签: c++ c++11 rtti typeid


【解决方案1】:

有些类是多态的,有些是非多态的。

一个多态类有一个或多个虚函数(可能继承),一个非多态类有零个虚函数。

你的 A 和 B 是非多态的。

A 和 B 的多态版本将表现出您想要的行为:

#include <iostream>
#include <typeinfo>

using namespace std;

struct A
{
    virtual ~A() {}; // add virtual function
};

class B : public A
{
};

A* a = new A();
A* a2 = new B();
B* b = new B();

int main()
{
    cout << (typeid(*a) == typeid(A)) << endl; // -> 1
    cout << (typeid(*a2) == typeid(A)) << endl; // -> 0 <-- CHANGED
    cout << (typeid(*b) == typeid(A)) << endl; // -> 0

    cout << (typeid(*a) == typeid(B)) << endl; // -> 0
    cout << (typeid(*a2) == typeid(B)) << endl; // -> 1 <-- CHANGED
    cout << (typeid(*b) == typeid(B)) << endl; // -> 1
}

多态类的实例在运行时存储其最派生对象的动态类型。

(在您的示例中,a2 是指向 A 的类型,并且指向 A 类型的对象,但是该对象只是 基类子对象 B 类型的最派生对象。在查询a2 时,您想要得到的是这个最派生对象B 的类型。为此,您需要一个多态类。)

这就是多态类如何支持最派生对象的dynamic_casttypeid(以及虚函数分派)。

非多态类没有这个信息,所以它们只能报告编译时已知的静态类型。非多态类比多态类更紧凑和高效。这就是为什么不是所有的 C++ 类都是多态的。该语言让程序员选择性能和功能之间的权衡。例如:

struct X { int x; };
struct Y : X {};
struct Z : Y {};

在我的系统上,非多态Zsizeof(Z) == 4 bytes,与int 相同。

struct X { int x; virtual ~X() {}; };
struct Y : X {};
struct Z : Y {};

现在在使Z 多态之后,sizeof(Z) == 16 bytes。所以 Z 数组现在大了 300%,因为每个 Z 实例都必须在运行时存储其类型信息。

【讨论】:

  • @Sharth:不,that's not true;在任何一种情况下你都不会得到它。
  • @LightnessRacesinOrbit,@prosseek:感谢您的指正!我原以为这是= default 案的主要原因之一。
  • @sharth:那会很好,但可惜不是。
  • cmets 是关于一个现已删除的错误声明,即使用 = default 而不是 {} 将禁止默认移动构造函数生成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 2011-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多