C ++类构造函数可以知道它的实例名称吗?

时间:2009-11-25 09:51:25

标签: c++ class constructor instance

是否可以从类方法中知道对象实例名称/变量名称?例如:

#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;
}

11 个答案:

答案 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 ++机制允许您对它们执行任何操作。 是否有可能创建适用于平台的解决方案?可能。人们必须在内存中分析进程的映像,根据特定的格式解析它,找出调试符号(和帧)并将它们映射到地址。本质上,调试自己。 值得麻烦吗?不在我看来。