是否可以从类方法中知道对象实例名称/变量名称?例如:
#include <iostream>
using namespace std;
class Foo {
public:
void Print();
};
void Foo::Print() {
// what should be ????????? below ?
// cout << "Instance name = " << ?????????;
}
int main() {
Foo a, b;
a.Print();
b.Print();
return 0;
}
答案 0 :(得分:27)
没有。变量名是针对程序员的,编译器可以看到地址。
提供有关其程序的元数据/反射的其他语言可能提供此功能,C ++不是这些语言之一。
答案 1 :(得分:25)
不是语言本身,但你可以编写类似的代码:
#include <iostream>
#include <string>
class Foo
{
public:
Foo(const std::string& name) { m_name = name;}
void Print() { std::cout << "Instance name = " << m_name << std::endl; }
private:
std::string m_name;
};
int main()
{
Foo a("a");
Foo b("b");
a.Print();
b.Print();
return 0;
}
答案 2 :(得分:16)
编译代码中不存在变量名。
但是,您可以使用一些#define
来获取预处理中的名称,并在编译之前填充名称。
这样的事情:
#define SHOW(a) std::cout << #a << ": " << (a) << std::endl
// ...
int i = 2;
SHOW (i);
答案 3 :(得分:9)
这意味着什么?
void f(T const& p) {
cout << p.name();
}
T r() {
T c;
return c;
}
void g() {
T a;
cout << a.name();
T & b = a;
cout << b.name();
T * ptr = &b;
cout << ptr->name();
T d = r();
cout << d.name();
}
你会期待什么?每次“一次”?那么c / d呢?
答案 4 :(得分:8)
变量名称无法在编译后继续存在。您可以做的最好的事情是将变量名称传递给对象构造函数,并使用宏将其存储在对象中。后者将导致非常丑陋的代码,所以你只想把它作为最后的手段。
答案 5 :(得分:7)
赏金: 这是我曾经创造过的最大,最恶心的黑客之一,但在我看来,它足以满足调试原因
#include <iostream>
#include <typeinfo>
#define DEBUG_INSTANCE( classtype, name ) class _ ## classtype ## _INSTANCE_ ## name ## _ : public classtype \
{ \
public: \
_ ## classtype ## _INSTANCE_ ## name ## _ (){ } \
}; \
_ ## classtype ## _INSTANCE_ ## name ## _ name
class Foo {
public:
virtual void _MakeTypeIDRunTime() { }
// A virtual method in the class forces typeid(*this) to be used runtime rather than compiled
// See: https://stackoverflow.com/a/6747130/1924602
void Print();
};
void Foo::Print() {
std::cout << "Instance name = " << typeid(*this).name() << std::endl;
}
int main()
{
DEBUG_INSTANCE(Foo, a);
DEBUG_INSTANCE(Foo, b);
a.Print();
b.Print();
system("PAUSE");
return 0;
}
输出:
Instance name = ?AV_Foo_INSTANCE_a_@?1?main@
Instance name = ?AV_Foo_INSTANCE_b_@?1?main@
Press any key to continue . . .
此宏将创建一个继承Foo的类,name包含实例名称。唯一的限制是Foo有一个默认构造函数,并且必须包含一个虚方法,以便typeid接受继承的类并在运行时调用。有关更好的解释,请参阅https://stackoverflow.com/a/6747130/1924602
如果您使用__VA_ARGS__
宏
答案 6 :(得分:5)
实例当然可以从类方法中知道它的名称:
#include <iostream>
class Foo {
public:
void Print() { std::cout << "Instance name = " << this << std::endl; }
};
int main() {
Foo a, b;
a.Print();
b.Print();
return 0;
}
将产生类似于此的输出:
Instance name = 0x7fff502b8b48
Instance name = 0x7fff502b8b40
至于知道变量名,肯定是不可能的。对象的存在并不意味着存在变量 - 这个例子:
new Foo();
将在剩余的过程中存在,但永远不会与任何变量相关联。变量的语言概念没有反映在所述变量的内容中,并且语言变量和对象之间的任何潜在关系仅在生成的代码中表示,而不在生成的数据或元数据中表示。当然,除非已经指出,否则访问调试信息不是语言的一部分。
答案 7 :(得分:1)
语言本身是不可能的。但是,您可以使用预处理器来获取它。但它不是很清楚,如果你的类有不同的构造函数,你必须要小心。你也必须在每节课中都这样做。
我将Steven Keith的例子与#define
预处理器结合使用:
#include <iostream>
#include <string>
using namespace std;
class Foo
{
public:
Foo(const string& name) : m_name(name) {}
void Print() { cout << "Instance name = " << m_name << endl; }
private:
string m_name;
};
#define DRESSED_Foo(var) Foo var(#var)
int main()
{
DRESSED_Foo(a);
DRESSED_Foo(b);
a.Print();
b.Print();
return 0;
}
答案 8 :(得分:1)
This is not possible "Directly", consider this simple program;
// stove.cpp
#include <string.h>
#include <stdio.h>
#include <iostream>
using namespace std;
class Foo {
char* t;
size_t length;
public:
Foo()
{
t = new char(8);
t = static_cast<char*>(static_cast<void*>(this));
}
void Print();
};
void Foo::Print() {
// what should be ????????? below ?
cout << this << " " << strlen (t) << t << endl;
}
int main() {
Foo a;
a.Print();
Foo b;
b.Print();
return 0;
}
you can check the value of t in gdb for both a and b objects,
1) run binary in gdb and put breakpoints on lines where both objects a and b gets created.
2) for both objects a and b , after creation (or in print function, check
print this
print t
18 }
(gdb) print this
$1 = (Foo * const) 0x7fffffffe6e0
(gdb) print t
$2 = 0x7fffffffe6e0 "\340\346\377\377\377\177"
...
...
...
30 Foo b;
(gdb) s
Foo::Foo (this=0x7fffffffe6d0) at stov.cpp:15
15 t = new char(8);
(gdb) n
16 t = static_cast<char*>(static_cast<void*>(this));
(gdb) n
18 }
(gdb) print this
$3 = (Foo * const) 0x7fffffffe6d0
(gdb) print t
$4 = 0x7fffffffe6d0 "\320\346\377\377\377\177"
答案 9 :(得分:0)
这是不可能的。 C ++没有像.NET平台那样的“反射”概念。 但是MFC库有CRunTime类 - 你可以看看例如。
答案 10 :(得分:0)
就C ++而言,调试符号不存在。因此,没有C ++机制允许您对它们执行任何操作。 是否有可能创建适用于平台的解决方案?可能。人们必须在内存中分析进程的映像,根据特定的格式解析它,找出调试符号(和帧)并将它们映射到地址。本质上,调试自己。 值得麻烦吗?不在我看来。