是否也可以获取对象名称?
#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 ++是否提供了实现此目的的任何机制?
答案 0 :(得分:65)
您可以使用预处理器显示变量的名称。例如
#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()的结果是受损的类名,以获得demangled version使用
#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
其他编译器可能使用不同的命名方案。
答案 1 :(得分:17)
使用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)];
}
答案 2 :(得分:8)
您希望[classname]为'one'且[objectname]为'A'吗?
如果是这样,这是不可能的。这些名称只是程序员的抽象,实际上并不用于生成的二进制代码。您可以为类提供一个静态变量classname,您可以将其设置为“one”,也可以通过方法或构造函数直接赋值的普通变量objectname。然后,您可以查询这些方法以获取类和对象名称。
答案 3 :(得分:7)
要获取没有修改内容的类名,可以在构造函数中使用 func 宏:
class MyClass {
const char* name;
MyClass() {
name = __func__;
}
}
答案 4 :(得分:4)
您可以尝试使用"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”宏,并定义一个可以调用静态模板函数的“classname”函数。
编辑3:考虑一下......早上第一件事就是明显不好,因为您可以定义一个成员函数“classname()”,如下所示:
std::string classname()
{
return "MyClass";
}
可以宏观化如下:
DefineClassName( className ) \
std::string classname() \
{ \
return #className; \
}
然后你可以简单地放弃
DefineClassName( MyClass );
在定义它时进入类......
答案 5 :(得分:4)
只需编写简单的模板:
template<typename T>
const char* getClassName(T) {
return typeid(T).name();
}
struct A {} a;
void main() {
std::cout << getClassName(a);
}
答案 6 :(得分: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*
答案 7 :(得分:0)
您可以尝试以下方法:
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>();
}