Подтвердить что ты не робот

Как получить имя класса из объекта С++?

Возможно ли получить имя объекта?

#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

Предоставляет ли С++ какой-либо механизм для достижения этого?

4b9b3361

Ответ 1

Вы можете отобразить имя переменной с помощью препроцессора. Например,

#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

Другие компиляторы могут использовать разные схемы именования.

Ответ 2

использовать 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)];
}

Ответ 3

Вы хотите, чтобы [имя_файла] было "одним" и [имя_объекта] равным "A"?

Если это так, это невозможно. Эти имена являются только абстракциями для программиста и фактически не используются в двоичном коде, который сгенерирован. Вы можете присвоить классу статическую переменную classname, которую вы установили в "one" и обычное имя переменной objectname, которое вы бы назначили напрямую, с помощью метода или конструктора. Затем вы можете запросить эти методы для имен классов и объектов.

Ответ 4

Чтобы получить имя класса без искажений, вы можете использовать макрос func в конструкторе:

class MyClass {
    const char* name;
    MyClass() {
        name = __func__;
    }
}

Ответ 5

Вы можете попробовать использовать "typeid" .

Это не работает для имени объекта, но вы знаете имя объекта, поэтому вам просто нужно его где-то хранить. Компилятору все равно, что вы начертили объект.

Однако стоит помнить, что вывод typeid является специфическим для компилятора, поэтому даже если он создает то, что вам нужно, на текущей платформе он не может быть другим. Это может быть или не быть проблемой для вас.

Другое решение - создать какую-то оболочку шаблона, в которой вы храните имя класса. Затем вам нужно использовать частичную специализацию, чтобы вернуть ему правильное имя класса. Это имеет преимущество рабочего времени компиляции, но значительно сложнее.

Изменить: быть более явным

template< typename Type > class ClassName
{
public:
    static std::string name()
    {
        return "Unknown";
    }
};

Тогда для каждого класса somethign liek следующее:

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" в каждый класс, который вы создали, и определить функцию "имя класса", которая вызовет функцию статического шаблона.

Edit3: И подумайте об этом... Очевидно, что плохая публикация первой вещи утром, как вы можете, просто определить функцию-член "classname()" следующим образом:

std::string classname()
{
     return "MyClass";
}

который может быть macro'd следующим образом:

DefineClassName( className ) \
std::string classname()  \
{ \
     return #className; \
}

Затем вы можете просто просто

DefineClassName( MyClass );

в класс, как вы его определяете...

Ответ 6

Просто напишите простой шаблон:

template<typename T>
const char* getClassName(T) {
  return typeid(T).name();
}

struct A {} a;

void main() {
   std::cout << getClassName(a);
}

Ответ 7

Улучшение для ответа @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*