开发者

Can a C++ Class Constructor Know Its Instance Name?

Is it possible to know the object instance name / variable name from within a class method? For example:

#include <iostream>

using namespace std;

class Foo {
     pub开发者_JAVA技巧lic:
          void Print();
};

void Foo::Print() {
     // what should be ????????? below ?
     // cout << "Instance name = " << ?????????;
}

int main() {
    Foo a, b;
    a.Print();
    b.Print();
    return 0;
}


No. Variable names are for the programmer, the compiler sees addresses.

Other languages that provide meta-data/reflection about their program might provide this functionality, C++ isn't one of those languages.


Not with the language itself, but you could code something like:

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


Variable names do not exist in the compiled code.

However you can use some #define to get the name in preprocessing and let the names be populated before the compile.

Something like this:

#define SHOW(a) std::cout << #a << ": " << (a) << std::endl
// ...
int i = 2;
SHOW (i);


What would that mean?

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();
}

What would you expect? "a" each time? And what about c/d?


Variable names don't survive compilation. The best you can do is to pass the variable name into the object constructor and store it inside the object by using a macro. The latter will lead to really ugly code so you would only want this as a last resort.


For the bounty: This is one of the biggest and most disgusting hacks I've ever created but its good enough for debug reasons in my opinion

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

Output:

Instance name = ?AV_Foo_INSTANCE_a_@?1?main@
Instance name = ?AV_Foo_INSTANCE_b_@?1?main@
Press any key to continue . . .

This macro will create a class that inherits Foo and name contains the instance name. Only limitation is that Foo has a default constructor and must contain a virtual method in order for typeid to accept inherited classes and be called used at runtime. See https://stackoverflow.com/a/6747130/1924602 for a better explanation

Might be possible to support constructors if you use the __VA_ARGS__ macro


It is certainly possible for an instance to know its name from within the class method:

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

will produce the output similar to this:

Instance name = 0x7fff502b8b48
Instance name = 0x7fff502b8b40

As for knowing the variable name, it is certainly not possible. The existence of the object does not imply the existence of the variable - this instance:

new Foo();

will exist for the remaining duration of the process, yet will never be associated with any variable. The language concept of variables is not reflected in the contents of said variables, and any potential relation between language variable and an object is expressed only in the generated code and not in generated data or meta-data. Barring of course the access to the debug information which, as already pointed out, is not part of the language.


It is not possible with the language itself. However, you can use preprocessor to get it. But it is not going to be clear and you will have to be careful if your classes have different constructors. Also you will have to do it in each class.

I reuse the example of Steven Keith in combination with #define preprocessor:

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


The keyword this

I'm new to programming, but having studied class structure I believe what you might be looking for is the keyword this. As in the example below (taken from cplusplus.com), you can see that this is used anywhere the class needs to refer to itself.

Therefore, it is possible for a constructor to do this as well.

// example on this
#include <iostream>
using namespace std;

class Dummy {
  public:
    bool isitme (Dummy& param);
};

bool Dummy::isitme (Dummy& param)
{
  if (&param == this) return true;
  else return false;
}

int main () {
  Dummy a;
  Dummy* b = &a;
  if ( b->isitme(a) )
    cout << "yes, &a is b\n";
  return 0;
}

http://www.cplusplus.com/doc/tutorial/templates/


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"


It is not possible. C++ does not have a concept of "reflection" like .NET platform. But MFC library has CRunTime class - you can see for example.


Debug symbols do not exist as far as C++ is concerned. As a result, no C++ mechanism allows you to do anything with them. Would it be possible to create platform-specific solution which would work? Possible. One would have to analyze the image of the process in memory, parse it according to specific format, figure out debug symbols (and frames) and map them to addresses. Essentially, debug itself. Does it worth the trouble? Not in my opinion.


You can do it using #define. Define a macro which would save variable name inside class:

#include <iostream>
#include <string>

using namespace std;

#define CREATE_FOO(f) Foo f = Foo(#f);

class Foo {
     public:
          void Print() const;
          Foo(string s): name(s) {};
     protected:
          string name;

};

void Foo::Print() const  {
     cout << "Instance name = " << name;
}


int main() {
    CREATE_FOO(a);
    CREATE_FOO(b);
    a.Print();
    b.Print();
    return 0;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜