2011-10-08 188 views
19

在C++中,当我们使用typeid来获取对象或类的类型名称时,它将显示装饰(损坏)的字符串。我用cxxabi来还原函数是:在C++中删除类型名称的命名空间

#include <cxxabi.h> 
#include <typeinfo> 

namespace MyNamespace { 

class MyBaseClass 
{ 
public: 
    const std::string name() 
    { 
     int status; 
     char *realname = abi::__cxa_demangle(typeid (*this).name(),0,0, &status); 
     std::string n = realname; 
     free(realname); 
     return n; 
    } 
}; 

} 

int main() 
{ 
    MyNamespace::MyBaseClass h; 
    std::cout << h.name() << std::endl; 
} 

输出在gcc是:

了myNameSpace :: MyBaseClass

我需要从上面的字符串中删除MyNamespace:: 我可以通过字符串操作删除它们

但是 是否有标准方式用cxxabi或其他库来做到这一点或有明确的解决方案? (至少在gcc和Visual C++之间可移植)

+2

+1,内容翔实的问题。 – iammilind

+0

IIRC对于任何一个类,只要返回相同的字符串(例如“godzilla”)就可以合法执行。 – 6502

+0

您可能希望对类和名称空间使用不同的命名约定,以便您可以立即看到哪个是“X :: Y :: Z :: MyType”中的哪一个。 –

回答

8

没有标准的方法来做到这一点,因为没有标准的方法来做名称修改。如何表示名称是故意未指定的。 C++标准中没有ABI。您正在使用的函数abi::__cxa_demangle是Itanium C++ ABI的一部分。该功能可能存在也可能不存在。至于如何使用Itanium C++ ABI来做你想做的事情,他们故意不提供这样的能力。

3

我不知道这是否符合您的需求,但我喜欢提及它。

你可以做些事情来获得你写的类的名字。它可以被认为是gcc和Visual C++之间可移植的。

在GCC有一种神奇变量命名__ FUNCTION __作为gnu c language extensions的一部分,该处理为可变,在C++。 (根据GCC版本对C进行处理。)

在Visual Studio中,有一个预定义的宏,它具有相同的名称并执行相同的工作。说明是here

您使用__ 功能 __获取当前函数的名称。因此,要获取类的名字,可能是你可以用它在类的构造函数是这样的:

namespace MyNamespace 
{ 
    class MyBaseClass 
    { 
    public: 
     MyBaseClass(): myName(__FUNCTION__){} 
     string name() { return myName; } 
    private: 
     string myName; 
    }; 
} 

所以,你会得到"MyBaseClass"回应,如果你调用这个类的一个实例的name()功能。

+0

但是,这种方法有一个问题,它不能在派生类中使用'name()'返回派生类名! (并且每个派生类必须再次覆盖它的构造函数) – deepmax

+0

@MasoudM。它不是一个标准的C++特性,而不是特定于gcc和VS.但即使在旧版本中也有提供。你可以检查有关的链接。是的,你对派生类问题是正确的。我现在无法弄清楚如何克服这一点。但应该有一种方法:) – etipici

+0

'__func__'被添加到C++ 11中,以正式提供这种功能,尽管以隐藏变量而非宏的形式提供。 MSVC目前还不支持它,尽管伪装很容易。 –

1

如果你只是想定义一个成员函数,它将返回类的字符串名称,没有名称空间,那么我想知道为什么你甚至会使用cxxabi甚至__FUNCTION__或其他任何东西,除了简单这样做:

namespace MyNamespace 
{ 
    class MyBaseClass 
    { 
    public: 
     //make the function const as well 
     std::string name() const { return "MyBaseClass"; } 
    }; 
} 

我的意思是,你对类的实现完全控制,那么为什么使其复杂化的时候只是一个返回语句够吗?您可以添加另一个成员函数,以及:

std::string fullname() const { return "MyNamespace::MyBaseClass"; } 

看一看这个有点关系的话题,也许你会得到更多的线索:

+0

thnx为答案,但它之前讨论过,我发现我的项目需要一个奇怪的模式一个很好的做法:[http://stackoverflow.com/questions/7691697/](http://stackoverflow.com/questions/ 7691697 /) – deepmax

+0

@MasoudM .:我刚刚添加了一个链接。看看这个。 – Nawaz

1

我调查cxxabi等这个问题的C++库,并没有任何预定义的方法来删除命名空间(至少在我的谷歌搜索)。

我想知道为什么你不想操纵字符串?!

的最佳解决方案和完全便携式(在gcc和VC++测试)是simipily下面:

return n;

return n.substr(n.find_last_of(':')+1);

当从上次搜索n为冒号(= lastColorPos)并从lastColorPos截取字符串结束,它是定义为的类名。

+3

这也删除类名称以及命名空间名称。考虑'struct Foo {struct Bar {...}; ...};'。 –

+2

为了阐明David的观点,考虑一下这个答案对于一个名为“SomeType '的类应该做些什么。 – arman

0
std::string removeNS(const std::string & source, const std::string & namespace_) 
{ 
    std::string dst = source; 
    size_t position = source.find(namespace_); 
    while (position != std::string::npos) 
    { 
     dst.erase(position, namespace_.length()); 
     position = dst.find(namespace_, position + 1); 
    } 
    return dst; 
} 

int main() 
{ 
    MyNamespace::MyBaseClass h; 
    std::cout << removeNS(h.name(), "MyNamespace::") << std::endl; 
} 
相关问题