Adam Dempsey
Adam Dempsey

Reputation: 2962

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 {
     public:
          void Print();
};

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

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

Upvotes: 17

Views: 12135

Answers (14)

PeteDD
PeteDD

Reputation: 1

class Food {
  private:
    uint8_t m_Temperature;  // cooking temperature

  public:
    //constructor
    Food (uint16_t Temperature) {
      m_Temperature = Temperature;
    }
    //forward declaration
    void CookIt(uint16_t NewTemperature);
    
};  // class

Food Burger(123);
Food Fries(233);

void Food::CookIt(uint16_t NewTemperature) {
  Serial.print("I am cooking ");
  if(this==&Burger) Serial.print("burger");
  if(this==&Fries)  Serial.print("fries");
  Serial.print(" at ");
  Serial.print(NewTemperature);
  Serial.println(" Deg C");
  Serial.println();

}

Upvotes: 0

Naumann
Naumann

Reputation: 407

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"

Upvotes: 0

EvgeniyZh
EvgeniyZh

Reputation: 905

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

Upvotes: 0

ganrob
ganrob

Reputation: 39

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/

Upvotes: 1

Leon
Leon

Reputation: 89

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.

Upvotes: 5

Steven Keith
Steven Keith

Reputation: 1799

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

Upvotes: 25

blashser
blashser

Reputation: 1031

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

Upvotes: 1

otc
otc

Reputation: 441

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

Upvotes: 8

SergeyA
SergeyA

Reputation: 62553

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.

Upvotes: 0

Luc Hermitte
Luc Hermitte

Reputation: 32926

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?

Upvotes: 9

Svetlozar Angelov
Svetlozar Angelov

Reputation: 21660

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

Upvotes: 16

Captain Comic
Captain Comic

Reputation: 16196

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.

Upvotes: 0

sharptooth
sharptooth

Reputation: 170469

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.

Upvotes: 8

GManNickG
GManNickG

Reputation: 503805

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.

Upvotes: 29

Related Questions