Вопрос по c++ – Печать имени производного класса в базовом классе

7

Как можно вывести имя производного класса из базового класса, не цепляя конструкторы до конца. Другими словами, возможно ли сделать это строго из базового класса, не добавляя код в каждый производный класс?

Это пример того, что я получил, и если есть способ, которым я хотел бы избавиться от цепочки конструктора.

EDIT: В идеале я ищу что-то, чтобы добавить в базовый класс, не редактируя все производные классы. На данный момент мой настоящий код имеет ~ 17 классов (с необходимостью большего), поэтому что-то, что могло бы выполнять работу прямо из базового класса, было бы идеальным. Даже если это зависит от компилятора (g ++ или clang).

#include <iostream>

class Base {
public:
    Base(std::string id) {
            std::cout<<"Creating "<<id<<std::endl;
    }
};

class Child : Base {
public:
    Child(std::string id) : Base(id) {}
    Child() : Base(typeid(this).name()) {}
};

class GrandChild : Child {
public:
    GrandChild(std::string id) : Child(id) {}
    GrandChild() : Child(typeid(this).name()) {}
};

class GrandGrandChild : GrandChild {
public:
    GrandGrandChild(std::string id) : GrandChild(id) {}
    GrandGrandChild() : GrandChild(typeid(this).name()) {}
};



int main() {
    GrandGrandChild *A = new GrandGrandChild();
    GrandChild *B = new GrandChild();
    Child *C = new Child();

    return 0;
}

Какие отпечатки:

Creating GrandGrandChild
Creating GrandChild
Creating Child

Но с скомпилированным добавленным префиксом.

Я намерен использовать его исключительно для целей отладки, поэтому было бы удобно что-то добавить в базовый класс. NFA
Я пытаюсь имитировать реальный код, который у меня есть. Выше приведен только пример, иллюстрирующий функциональность, которую я ищу. Все мои объекты создаются динамически. NFA
Я делаю то же самое, что и вы. Отладка процесса создания объектов. Мне интересно, что ты делал в конце? Ratata Tata
Использовать полиморфизм, а не RTTI, для этого и нужен полиморфизм. Griwes
не создавать экземпляры объектов динамически, например,GrandGrandChild A; было бы вполне достаточно, чтобы оценить конструктор по умолчанию. moooeeeep

Ваш Ответ

3   ответа
0

Поскольку вы указываете, что это для отладки, вы можете положиться на виртуальное наследование, чтобы избежать передачи имени через все промежуточные производные классы, и вместо этого передать его непосредственноBase, Также,Base может быть изменен, чтобы взять конструктор шаблона, чтобы упростить вещи для производных классов.

class Base {
public:
    template <typename DERIVED>
    Base (DERIVED *d) {
        std::cout << "Creating " << typeid(*d).name() << std::endl;
    }
};

class Child : virtual public Base {
public:
    Child () : Base(this) {}
};

class GrandChild : public Child, virtual public Base {
    GrandChild () : Base(this) {}
}

class GrandGrandChild : public GrandChild, virtual public Base {
    GrandGrandChild () : Base(this) {}
}
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded NFA
Error: User Rate Limit ExceededvirtualError: User Rate Limit ExceededChildError: User Rate Limit ExceededGrandChildError: User Rate Limit ExceededBase.
9

К сожалению, нет простого решения.

Проблема в том, что создание полиморфных объектов довольно сложно, в настоящий момент вы создаетеBase частьChild класс, вы строитеBase тем не менее, неChild (потому что пытается получить доступChild участники были бы бессмысленными, они еще не были построены!)

Таким образом, все способы извлечения динамической информации (известной как RTTI или информация о типе RunTime) являются добровольными.locked down чтобы предотвратить такую ошибку.

По симметричным причинам то же самое происходит в деструкторе.


Теперь только конструктор и деструктор так заблокированы, поэтому вы можете прекрасноname() метод, который с радостью вернетtrue имя динамического типа экземпляра во всех остальных случаях:

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

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

Теперь, что касается "странного" выводим, что каждая реализация (компилятор) имеет право предоставлять свой собственный вывод здесь (и они даже не должны быть разными для разных типов, сумасшествие, да!). Вы, кажется, используете gcc или clang.

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

Error: User Rate Limit Exceeded NFA
0

Вы можете предоставить функцию инициализации, которую нужно вызывать из каждого конструктора.

class Base {
protected:
  Base() { init(typeid(this).name()); }
  void init(std::string id) {
    std::cout<<"Creating "<<id<<std::endl;
  }
};

Вам как-то нужно убедиться, что последующие модули благополучно заменят изменения предыдущих:

Creating P4Base
Creating P5Child
Creating P10GrandChild
Creating P15GrandGrandChild
Creating P4Base
Creating P5Child
Creating P10GrandChild
Creating P4Base
Creating P5Child

I intend to use it purely for debugging purposes, which is why something to throw into the base class would be convenient.

Вы рассматривали возможность добавления макроса в ваш код для вывода отладочной информации?

#ifdef DEBUG
  #define PRINT_CLASSNAME std::cout<<"Creating "<<id<<std::endl;
#else
  #define PRINT_CLASSNAME ;
#endif

Вам нужно добавить его в ваши конструкторы один раз, но если вы хотите отключить его (временно), вы просто отменяете определение?

Error: User Rate Limit Exceeded NFA
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы