2011-10-08 48 views
19

Trong C++, khi chúng ta sử dụng typeid để lấy tên kiểu của một đối tượng hoặc một lớp, nó sẽ hiển thị một chuỗi được trang trí (xâu chuỗi). Tôi sử dụng cxxabi để demangle nó:Loại bỏ không gian tên của tên loại trong 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; 
} 

Sản lượng trong gcc là:

MyNameSpace :: MyBaseClass

tôi cần phải loại bỏ MyNamespace:: từ chuỗi trên. tôi có thể xóa chúng bằng cách xử lý chuỗi .

Nhưng có cách nào tiêu chuẩn với cxxabi hoặc các thư viện khác để làm điều này hoặc giải pháp rõ ràng? (Ít nhất là di động giữa gcc và Visual C++)

+2

+1, câu hỏi thông tin. – iammilind

+0

IIRC sẽ là hợp pháp cho việc triển khai tuân thủ để chỉ trả lại cùng một chuỗi (ví dụ: "godzilla") cho bất kỳ lớp nào. – 6502

+0

Bạn có thể sử dụng các quy ước đặt tên khác nhau cho các lớp và không gian tên, để bạn có thể xem ngay lập tức cái nào trong đó có trong 'X :: Y :: Z :: MyType'. –

Trả lời

8

Không có cách tiêu chuẩn để làm điều này, vì không có cách tiêu chuẩn để làm tên mangling. Làm thế nào để đại diện cho tên đã được cố ý không xác định. Không có ABI trong tiêu chuẩn C++. Hàm bạn đang sử dụng, abi::__cxa_demangle, là một phần của Itanium C++ ABI. Chức năng đó có thể hoặc không tồn tại ở nơi khác.

Theo như cách để làm những gì bạn muốn bằng Itanium C++ ABI, họ cố ý không cung cấp khả năng như vậy.

3

Tôi không biết điều này có tương ứng với nhu cầu của bạn hay không nhưng tôi thích đề cập đến nó.

Có một số việc bạn có thể làm để lấy tên của lớp bạn đã viết. Và nó có thể được coi là di động giữa gcc và Visual C++.

Trong GCC có một biến kỳ diệu mang tên __ CHỨC NĂNG __ như một phần của gnu c language extensions, mà đối xử như một biến, trong C++. (Xử lý nó khác với C theo phiên bản GCC.)

Trong Visual Studio có macro được xác định trước có cùng tên và thực hiện cùng một công việc. Mô tả là here.

Bạn sử dụng __ FUNCTION __ để lấy tên của hàm hiện tại. Vì vậy, để có được tên của lớp, có thể là bạn có thể sử dụng nó trong constructor lớp như thế này:

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

Vì vậy, bạn sẽ có được "MyBaseClass" phản ứng nếu bạn gọi name() chức năng của một thể hiện của lớp này.

+0

nhưng, cách tiếp cận này có một vấn đề, nó không thể sử dụng trong các lớp dẫn xuất mà 'name()' trả về tên lớp dẫn xuất! (và mỗi lớp dẫn xuất phải ghi đè lên hàm tạo của nó một lần nữa) – deepmax

+0

@MasoudM. Nó không phải là một tính năng standad C++, thay vì cụ thể cho gcc và VS. Nhưng ngay cả trong các phiên bản cũ nó được cung cấp. Bạn có thể kiểm tra các liên kết về điều đó. Và có, bạn đúng về vấn đề lớp học có nguồn gốc. Bây giờ tôi không thể hiểu được cách khắc phục điều đó. Nhưng nên có một cách :) – etipici

+0

'__func__' đã được thêm vào C++ 11 để chính thức cung cấp chức năng này, mặc dù dưới dạng một biến ẩn chứ không phải là macro. MSVC không hỗ trợ nó, mặc dù giả mạo nó là dễ dàng đủ. –

1

Nếu bạn chỉ muốn xác định hàm thành viên sẽ trả về tên chuỗi của lớp, không có vùng tên, thì tôi tự hỏi tại sao bạn thậm chí sử dụng cxxabi hoặc thậm chí __FUNCTION__ hoặc bất kỳ thứ gì khác làm điều này:

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

tôi có nghĩa là bạn có quyền kiểm soát đầy đủ về việc thực hiện của lớp, thì tại sao làm cho nó phức tạp khi chỉ là một trở lại-tuyên bố là đủ? Bạn có thể thêm chức năng thành viên khác cũng như:

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

Hãy nhìn vào chủ đề nào liên quan này, có thể bạn sẽ nhận được nhiều gợi ý:

+0

Thnx cho câu trả lời, nhưng nó đã được thảo luận trước và tôi tìm thấy một thực hành tốt cho dự án của tôi mà cần một mô hình kỳ lạ: [http://stackoverflow.com/questions/7691697/](http://stackoverflow.com/questions/ 7691697 /) – deepmax

+0

@MasoudM .: Tôi vừa thêm một liên kết. Có một cái nhìn vào đó là tốt. – Nawaz

1

tôi điều tra cxxabi và khác c + + thư viện cho vấn đề này và không có bất kỳ phương pháp được xác định trước để loại bỏ không gian tên từ đó (ít nhất là trong googling của tôi).

Tôi tự hỏi tại sao bạn không muốn thao tác chuỗi?

giải pháp tốt nhất và hoàn toàn di động (thử nghiệm trong gcc và vC++) là simipily dưới đây:

return n;

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

Khi bạn tìm kiếm n cho một tràng từ cuối cùng (= lastColorPos) và bắt giữ chuỗi từ lastColorPos để kết thúc, đó là definetly tên lớp.

+3

Điều này cũng loại bỏ tên lớp cũng như tên không gian tên. Hãy xem xét 'struct Foo {struct Bar {...}; ...}; '. –

+2

Để làm rõ điểm của David, hãy suy nghĩ về câu trả lời này sẽ làm gì với một lớp có tên demangled '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; 
} 
Các vấn đề liên quan