如何在C++中获取动态类型名称?

3

如何获取动态类型名称?

class O {
public:
std::string typename(){ return typeid(*this).name(); }
}

class C  : public O { /* ... */ }

O* varb = new C();
cout << O->typename(); // <--- return class O instead of class C

我该如何解决这个问题?

4
typename 是一个关键字。 - undefined
5个回答

4
在我的Linux/Debian/Sid/x86-64系统上,该文件为:
// file raffa.cc
#include <iostream>
#include <fstream>
#include <typeinfo>
#include <string>

class O {
public:
    virtual std::string type_name() {
        return typeid(*this).name();
    }
    virtual ~O() {};
};

class C  : public O {
    int f;
public:
    C(int k) : O(), f(k) {};
    virtual ~C() {};
    /* ... */
};

using namespace std;

int main() {
    O* varb = new C(__LINE__);
    cout << varb->type_name() << endl; 
    delete varb;
    return 0;
}   

编译使用

g++-4.8 -std=c++11 -Wall -O raffa.cc -o raffa

在运行 ./raffa 时显示:

1C

前缀1可能是由于名称混淆。仔细查看此问题的答案以还原它。

PS:在实际生活中,避免使用裸指针并警惕内存泄漏,因此请不要直接复制我的代码而不理解这些问题!使用valgrind ...


  1. 拥有内存的原始指针。
  2. 泄露内存。请不要在示例中发布这样的糟糕代码,人们会在真实项目中复制它。
- undefined
5
原文:The OP (not me) used some raw pointer. People copying that blindly without understanding pointer and memory allocation issues deserve what they should.翻译:OP(不是我)使用了一些裸指针。那些盲目复制而不理解指针和内存分配问题的人,应该得到他们应得的结果。 - undefined
OP还使用typename作为成员名称,而你修复这个bug没有任何问题。也要修复内存泄漏! - undefined
@BasileStarynkevitch好的,那就纠正一下原帖。正如David所说,你没有问题修复其他错误。虽然我自己经常心怀恶意,但我们在这里是为了教和帮助,而不是归咎责备。 - undefined
@DavidHammen和KonradRudoph:改进了我的回答。 - undefined

3
声明返回类型为typename的函数时,请将其声明为virtual。否则,*this只会引用C-O子对象的部分。您还可以在C ++中搜索多态性。
编辑。正如“Cheers and hth. - Alf”指出的那样,声明某些函数为virtual就足以使类成为多态。而且,对于多态基类,声明析构函数为virtual是必须的。但是,您仍然需要将可能重新实现的所有函数声明为virtual。

更好的方法是将析构函数设为虚函数。只需要类具有多态性(拥有一些虚成员函数)即可。析构函数正好可以用于此,避免引入意外的定制点。 - undefined

2
"typename是C++中的保留关键字!请将O::type_name()设为虚函数,以便通过O*调用C::type_name:"
#include <iostream>
#include <memory>

class O {
public:
    virtual std::string type_name() { return typeid(*this).name(); }
    virtual ~O() {}
};

class C: public O {};

int main() {
    std::unique_ptr<O> varb { new C() };
    std::cout << varb->type_name();
}

看它跑!


2
给 O 添加一个虚析构函数。 - undefined
2
更好的方法是将析构函数设为虚函数。只要类是多态的(具有一些虚成员函数),这就足够了。而且,析构函数正是为此而设计的——避免引入意外的定制点。 - undefined
好观点,@Cheersandhth.-Alf。对我来说,将type_name()设为virtual更明确,但你说得对,一个virtual析构函数就足够了。 - undefined

1

你的代码中存在一些错误:

  • 首先,你不能使用typename作为自定义名称,它是C++关键字。
  • 其次,你不能使用

    O* varb = new C(); 
    cout << O->typename();
    

    因为你试图取消引用一个类名,这没有意义。你可能想要的是varb->typename()

关于typeid的用法...如果您想使用typeid在运行时动态返回指针所引用的类的名称,您应该使用类似于以下内容的语句:

#include <iostream>
#include <typeinfo>
using namespace std;

class O {
public:
    virtual void vfunction() // Just one virtual function in the base to make the derived polymorphic
    {
        cout << "hello";
    }
};

class C  : public O 
{
    public:
    C() {};
};



int main() 
{
    // your code goes here

    O* varb = new C(); // Declare an O* pointer to C

    cout << typeid(*varb).name(); // This will print out "C", runtime info

    cout << typeid(varb).name(); // This will print out "O*"

    return 0;
}

http://ideone.com/K2RGd5

请记住,一个类需要是多态的(也就是说,要继承一个带有虚函数的基类),才能使typeid在解引用指针时返回它所指向的运行时类。
这里有更多信息:https://dev59.com/vWbWa4cB1Zd3GeqPTRx2#11484105
注意:在上面的代码中,如果您使用的是gcc,您可能会看到不同于您原来使用的类名...这是由于gcc进行名称重整而自定义定义的,如果您想要真正的代码名称显示出来,您应该使用类似于的东西。
#include <iostream>
#include <typeinfo>
#include <cxxabi.h> // Needed to demangle in gcc
using namespace std;

class O {
public:
    virtual void vfunction()
    {
        cout << "hello";
    }
};

class C  : public O 
{
    public:
    C() {};
};



int main() {
    // your code goes here

    O* varb = new C();

    int status;
    // Demangle symbols
    cout << __cxxabiv1::__cxa_demangle( typeid(*varb).name(), nullptr, 0, &status ); << endl;
    cout << __cxxabiv1::__cxa_demangle( typeid(varb).name(), nullptr, 0, &status );

    return 0;
}

1

如果不指定每个类型名称,您无法以可移植的方式获得漂亮易读的类型名称。

但是,在使用Visual C++时,typeid::name的名称易于阅读,而在g++中它们也不错。

因此,只需更改当前的代码即可。

class O {
public:
std::string typename(){ return typeid(*this).name(); }
}

class C  : public O { /* ... */ }

O* varb = new C();
cout << O->typename(); // <--- return class O instead of class C

class O {
public:
    std::string type_name() const { return typeid(*this).name(); }
    virtual ~O() {}
};

class C  : public O { /* ... */ };

O* varb = new C();
cout << varb->type_name(); // <--- return class O instead of class C

在哪里

  • 函数名typename(C++关键字)已更改为type_name
  • 该函数被设置为const,以便可以在const对象上调用它。
  • 添加了虚析构函数,使类具有多态性(typeid以多态方式工作的要求)。
  • 在两个类定义的末尾添加了分号。
  • O->更改为varb->:无法引用类。

免责声明:代码未经编译器处理(但当您发布问题时,最好先将代码放入编译器中!)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接