2014-01-11 2 views
1

Как получить динамическое имя типа?Как получить динамическое имя типа в C++?

class O { 
public: 
std::string typename(){ return typeid(*this).name(); } 
} 

class C : public O { /* ... */ } 

O* varb = new C(); 
cout << O->typename(); // <--- return class O instead of class C 

Как я могу это устранить?

+4

'typename' - это ключевое слово. –

+1

Скомпилирует? –

ответ

3

Объявите свою функцию, возвращающую имя-типа, как virtual. В противном случае *this будет относиться только к части C - O подобъектом. Вы также можете использовать Google для полиморфизма в C++.

Редактировать. Как указано @ «Cheers and hth. - Alf», достаточно объявить как virtual, чтобы сделать класс полиморфным. И объявление деструктора virtual является обязательным для полиморфных базовых классов. Но вам все равно нужно объявить все функции, которые вы, возможно, переопределите, как virtual.

+0

Лучшим подходом является создание виртуального деструктора. Достаточно, чтобы класс был полиморфным (имеет * некоторую * функцию виртуального члена). И деструктор хорош для этого - избегая введения непреднамеренной точки настройки. –

2

typename является зарезервированным keyword в C++!

Сделать O::type_name()virtual, чтобы позволить C::type_name быть вызван через O*:

#include <iostream> 
#include <memory> 

class O { 
public: 
    virtual std::string type_name() { return typeid(*this).name(); } 
    virtual ~O() {} 
}; 

class C: public O {}; 

int main() { 
    std::unique_ptr<O> varb { new C() }; 
    std::cout << varb->type_name(); 
} 

See it run!

+2

и дать O виртуальный деструктор. – juanchopanza

+2

Лучше всего сделать деструктор виртуальным. Достаточно, чтобы класс был полиморфным (имеет некоторую виртуальную функцию-член). И деструктор хорош для этого - избегая введения непреднамеренной точки настройки. –

+0

Хорошая точка, @ Cheersandhth.-Альф. Создание 'type_name()' 'virtual' выглядит более явным для меня, но вы правы, что' virtual' dtor будет достаточно. – Johnsyweb

1

На моей/x86-64 системы Linux/Debian/Sid файл

// file raffa.cc 
#include <iostream> 
#include <fstream> 
#include <typeinfo> 
#include <string> 

class O { 
public: 
    virtual std::string type_name() { 
     return typeid(*this).name(); 
    } 
    virtual ~O() {}; 
}; 

class C : public O { 
    int f; 
public: 
    C(int k) : O(), f(k) {}; 
    virtual ~C() {}; 
    /* ... */ 
}; 

using namespace std; 

int main() { 
    O* varb = new C(__LINE__); 
    cout << varb->type_name() << endl; 
    delete varb; 
    return 0; 
} 

составлено с использованием

g++-4.8 -std=c++11 -Wall -O raffa.cc -o raffa 

отображается при запуске ./raffa:

1C 

Приставка 1, вероятно, из-за name mangling. См. внимательно отвечает на this question, чтобы его развязать.

PS: в реальной жизни избегайте указателей со стороны и бойтесь memory leaks, поэтому не копируйте мой код до конца, не понимая этих проблем! Используйте valgrind ...

+0

1) необработанные указатели, владеющие памятью. 2) утечка памяти. Пожалуйста, сделайте ** не ** отправьте такой код дерьма в качестве примера. Люди ** будут ** копировать его в реальных проектах. –

+2

OP (не я) использовал некоторый необработанный указатель. Люди, которые копируют это слепо, не понимая проблем с указателем и распределением памяти, заслуживают того, что им нужно. –

+0

OP также использовал 'typename' как имя участника, и у вас не было проблем с исправлением этой ошибки. Устраните утечку, тоже! –

1

Некоторые ошибки в коде:

  • Прежде всего, вы не можете использовать TypeName как пользовательское имя, это C++ ключевое слово.
  • Во-вторых, вы не можете использовать

    O* varb = new C(); 
    cout << O->typename(); 
    

    поскольку вы пытаетесь разыменовывать имя класса, и что не имеет никакого смысла. Вы, вероятно, имели в виду varb-> typename() в любом случае.

К использованию типа.если вы пытаетесь использовать TypeId вернуть динамически имя класса указатель со ссылкой (выполнения), вы должны использовать что-то вроде

#include <iostream> 
#include <typeinfo> 
using namespace std; 

class O { 
public: 
    virtual void vfunction() // Just one virtual function in the base to make the derived polymorphic 
    { 
     cout << "hello"; 
    } 
}; 

class C : public O 
{ 
    public: 
    C() {}; 
}; 



int main() 
{ 
    // your code goes here 

    O* varb = new C(); // Declare an O* pointer to C 

    cout << typeid(*varb).name(); // This will print out "C", runtime info 

    cout << typeid(varb).name(); // This will print out "O*" 

    return 0; 
} 

http://ideone.com/K2RGd5

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

Некоторые больше информации здесь: https://stackoverflow.com/a/11484105/1938163


Примечание: в приведенном выше коде, если вы используете GCC, вы можете увидеть различные имена классов, чем оригинал, который вы использовали .. это специально определено НКУ благодаря name mangling, и если вы хотите реальные имена код, чтобы показать, вы должны использовать что-то вроде

#include <iostream> 
#include <typeinfo> 
#include <cxxabi.h> // Needed to demangle in gcc 
using namespace std; 

class O { 
public: 
    virtual void vfunction() 
    { 
     cout << "hello"; 
    } 
}; 

class C : public O 
{ 
    public: 
    C() {}; 
}; 



int main() { 
    // your code goes here 

    O* varb = new C(); 

    int status; 
    // Demangle symbols 
    cout << __cxxabiv1::__cxa_demangle(typeid(*varb).name(), nullptr, 0, &status); << endl; 
    cout << __cxxabiv1::__cxa_demangle(typeid(varb).name(), nullptr, 0, &status); 

    return 0; 
} 
1

вы не можете получить хорошее имя типа удобочитаемый переносимым способом, без указания EAC h type name самостоятельно.

Однако, с Visual C++ имена typeid::name являются читабельными для человека, а с g ++ они не так уж плохи.

Так, просто изменить текущий код

class O { 
public: 
std::string typename(){ return typeid(*this).name(); } 
} 

class C : public O { /* ... */ } 

O* varb = new C(); 
cout << O->typename(); // <--- return class O instead of class C 

в

class O { 
public: 
    std::string type_name() const { return typeid(*this).name(); } 
    virtual ~O() {} 
}; 

class C : public O { /* ... */ }; 

O* varb = new C(); 
cout << varb->type_name(); // <--- return class O instead of class C 

где

  • Имя функции typename, что C++ ключевое слово, было изменено на type_name.
  • Функция была сделана const, так что ее можно вызвать на объекте const.
  • Добавлен виртуальный деструктор, чтобы сделать класс полиморфным (требование для typeid для работы полиморфным способом).
  • Точка с запятой была добавлена ​​в конце обоих определений классов.
  • O-> был изменен на varb->: вы не можете разыгрывать класс.

Отказ от ответственности: код не тронут руками компилятора (но когда вы отправляете вопрос, лучше сначала поставить код в компилятор!).

Смежные вопросы