83

是否也可以获取对象名称?

#include<cstdio>

class one {
public:
    int no_of_students;
    one() { no_of_students = 0; }
    void new_admission() { no_of_students++; }
};

int main() {
    one A;
    for(int i = 0; i < 99; i++) {
        A.new_admission();
    }
    cout<<"class"<<[classname]<<" "<<[objectname]<<"has "
        <<A.no_of_students<<" students";
}

我可以在哪里取名字,比如

[classname] = A.classname() = one
[objectname] = A.objectname() = A

C++ 是否提供任何机制来实现这一点?

4

8 回答 8

113

您可以使用预处理器显示变量的名称。例如

#include <iostream>
#define quote(x) #x
class one {};
int main(){
    one A;
    std::cout<<typeid(A).name()<<"\t"<< quote(A) <<"\n";
    return 0;
}

输出

3one    A

在我的机器上。将#标记更改为字符串,在预处理该行之后是

std::cout<<typeid(A).name()<<"\t"<< "A" <<"\n";

当然,如果你做类似的事情

void foo(one B){
    std::cout<<typeid(B).name()<<"\t"<< quote(B) <<"\n";
}
int main(){
    one A;
    foo(A);
    return 0;
}

你会得到

3one B

因为编译器不会跟踪所有变量的名称。

就像在 gcc 中发生的那样, typeid().name() 的结果是损坏的类名,以获取使用的损坏版本

#include <iostream>
#include <cxxabi.h>
#define quote(x) #x
template <typename foo,typename bar> class one{ };
int main(){
    one<int,one<double, int> > A;
    int status;
    char * demangled = abi::__cxa_demangle(typeid(A).name(),0,0,&status);
    std::cout<<demangled<<"\t"<< quote(A) <<"\n";
    free(demangled);
    return 0;
}

这给了我

one<int, one<double, int> > A

其他编译器可能使用不同的命名方案。

于 2010-09-06T06:04:45.007 回答
20

采用typeid(class).name

// 假设所有包含/命名空间等的说明性代码

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

struct A{};
int main(){
   cout << typeid(A).name();
}

重要的是要记住,这给出了实现定义的名称。

据我所知,没有办法在运行时可靠地获取对象的名称,例如代码中的“A”。

编辑2:

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

struct A{
};
struct B{
};

map<const type_info*, string> m;

int main(){
    m[&typeid(A)] = "A";         // Registration here
    m[&typeid(B)] = "B";         // Registration here

    A a;
    cout << m[&typeid(a)];
}
于 2010-09-06T05:50:19.343 回答
16

要在不修改内容的情况下获取类名,您可以在构造函数中使用func宏:

class MyClass {
    const char* name;
    MyClass() {
        name = __func__;
    }
}
于 2016-04-22T13:13:30.183 回答
8

你想让 [classname] 是 'one' 而 [objectname] 是 'A' 吗?

如果是这样,这是不可能的。这些名称只是程序员的抽象,实际上并没有在生成的二进制代码中使用。您可以给该类一个静态变量类名,您将其设置为“一”和一个普通变量对象名,您可以通过方法或构造函数直接分配它。然后,您可以在这些方法中查询类和对象名称。

于 2010-09-06T05:54:14.363 回答
7

只需编写简单的模板:

template<typename T>
const char* getClassName(T) {
  return typeid(T).name();
}

struct A {} a;

void main() {
   std::cout << getClassName(a);
}
于 2013-11-22T09:03:35.570 回答
6

您可以尝试使用"typeid"

这不适用于“对象”名称,但您知道对象名称,因此您只需将其存储在某个地方。编译器不在乎你给一个对象起什么名字。

不过,值得记住的是,typeid 的输出是编译器特定的东西,所以即使它在当前平台上产生了你所追求的东西,它也可能不会在另一个平台上产生。这对您来说可能是也可能不是问题。

另一种解决方案是创建某种模板包装器来存储类名。然后你需要使用部分特化来让它为你返回正确的类名。这具有工作编译时间的优点,但要复杂得多。

编辑:更明确

template< typename Type > class ClassName
{
public:
    static std::string name()
    {
        return "Unknown";
    }
};

然后对于每个类,一些事情如下:

template<> class ClassName<MyClass>
{
public:
    static std::string name()
    {
        return "MyClass";
    }
};

甚至可以宏化如下:

#define DefineClassName( className ) \
\
template<> class ClassName<className> \
{ \
public: \
    static std::string name() \
    { \
        return #className; \
    } \
}; \

让你,简单地,做

DefineClassName( MyClass );

最后要获取类名,您需要执行以下操作:

ClassName< MyClass >::name();

Edit2:进一步详细说明,您需要将此“DefineClassName”宏放入您创建的每个类中,并定义一个“类名”函数,该函数将调用静态模板函数。

Edit3:考虑一下......早上第一件事显然很糟糕,因为您不妨定义一个成员函数“classname()”,如下所示:

std::string classname()
{
     return "MyClass";
}

可以按如下方式进行宏化:

DefineClassName( className ) \
std::string classname()  \
{ \
     return #className; \
}

然后你可以简单地放下

DefineClassName( MyClass );

进入你定义的类......

于 2010-09-06T05:49:49.507 回答
4

你可以试试这个:

template<typename T>
inline const char* getTypeName() {
  return typeid(T).name();
}

#define DEFINE_TYPE_NAME(type, type_name)  \
  template<>                               \
  inline const char* getTypeName<type>() { \
    return type_name;                      \
  }

DEFINE_TYPE_NAME(int, "int")
DEFINE_TYPE_NAME(float, "float")
DEFINE_TYPE_NAME(double, "double")
DEFINE_TYPE_NAME(std::string, "string")
DEFINE_TYPE_NAME(bool, "bool")
DEFINE_TYPE_NAME(uint32_t, "uint")
DEFINE_TYPE_NAME(uint64_t, "uint")
// add your custom types' definitions

并这样称呼它:

void main() {
 std::cout << getTypeName<int>();
}
于 2019-10-31T13:33:08.507 回答
2

@Chubsdad 答案的改进,

//main.cpp

using namespace std;

int main(){
A a;
a.run();
}

//A.h
class A{
public:
 A(){};
 void run();
}

//A.cpp
#include <iostream>
#include <typeinfo>
void A::run(){
   cout << (string)typeid(this).name();
}

这将打印:

class A*
于 2015-02-03T14:33:32.457 回答