C++ 在基类中打印派生类名

C++ 在基类中打印派生类名,c++,C++,如何从基类打印出派生类名,而无需一直链接构造函数。换句话说,是否可以严格从基类执行此操作,而不在每个派生类中添加代码 这是我得到的一个例子,如果有一种方法我想摆脱构造函数链接 编辑: 理想情况下,我希望在基类中添加一些内容,而不必编辑所有派生类。目前,我真正的代码有17个类(需要更多),因此可以直接从基类完成这项工作的东西将是理想的。即使它是特定于编译器的(g++或clang) 但是在编译后添加了前缀。因为您指出这是为了调试,所以可以依靠虚拟继承来避免通过所有中间派生类传递名称,而是直接将其传递

如何从基类打印出派生类名,而无需一直链接构造函数。换句话说,是否可以严格从基类执行此操作,而不在每个派生类中添加代码

这是我得到的一个例子,如果有一种方法我想摆脱构造函数链接

编辑: 理想情况下,我希望在基类中添加一些内容,而不必编辑所有派生类。目前,我真正的代码有17个类(需要更多),因此可以直接从基类完成这项工作的东西将是理想的。即使它是特定于编译器的(g++或clang)


但是在编译后添加了前缀。

因为您指出这是为了调试,所以可以依靠虚拟继承来避免通过所有中间派生类传递名称,而是直接将其传递给
。另外,
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) {}
}
类基{
公众:
模板
基数(导出*d){

std::cout您可以提供需要从每个构造函数调用的初始化函数

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


我打算纯粹出于调试目的使用它,这就是为什么将一些东西扔进基类会很方便的原因

您是否考虑过向代码中添加宏以打印调试输出

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

#定义PRINT_CLASSNAME std::cout不幸的是,没有简单的解决方案

问题是构造多态对象相当复杂,在您构建
Child
类的
Base
子部分时,您仍然在构建
Base
,而不是
Child
(因为尝试访问
Child
成员将是无意义的,它们还没有被构建!)

因此,检索动态信息(称为RTTI或运行时类型信息)的所有方法都会自动锁定,以防止此类错误

出于对称的原因,在析构函数中也会发生同样的情况


现在,只有构造函数和析构函数被如此锁定,因此您完全可以拥有一个
name()
方法,该方法将在所有其他情况下愉快地返回实例的动态类型的真实名称:

class Base {
public:
    std::string name() const { return typeid(*this).name(); }
};
它将工作…除非您从构造函数或析构函数调用它,在这种情况下,它将报告静态类型

现在,就“奇怪”的输出而言,每个实现(编译器)都可以在这里提供自己的输出(对于不同的类型,它们甚至不需要不同,疯狂吧!)。您似乎在使用gcc或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;
}

有Demangler来解释这样的输出,或者如果你的程序足够简单并且他们的接口让你害怕,你可以简单地尝试手动解析它来删除错误。类的名称应该完整地显示出来,前面只是一些废话(基本上是名称空间和数字).

使用多态性,而不是RTTI,这就是多态性的用途。我打算纯粹为了调试目的而使用它,这就是为什么将一些东西放入基类会很方便的原因。不要动态实例化对象,例如,
grand孙子A;
就足以评估默认构造函数。我试图模仿我有真实的代码。上面只是一个例子来说明我正在寻找的功能。我所有的对象都是动态实例化的。我做的事情和你完全一样。调试对象创建的过程。我想知道,你最后做了什么?你不需要从
C继承
virtual
hild
孙辈
,仅基于
基础
的继承。目前我有约17个类(我希望我需要更多)这是一个基类的分支。这就是为什么我要寻找一些可以轻松添加到基类而不是单独编辑所有类的内容。也许我所要求的是不可能的…@NFA,您可以始终对其进行宏处理。您的新解决方案为我打印BaseNamex3。@NFA,我的建议是使用一种让您头痛的增量最小的解决方案当您添加新类时,现在就要咬紧牙关以某种方式修改所有类。您可以选择最适合自己的方式。这会删除构造函数链接,但我仍然需要在每个派生类中包含代码。我正在寻找一些解决方案,以便只转储到基类中。感觉这是编译器应该知道的信息。我希望即使使用一些特定于编译器的代码(g++/clang),也不会有问题如果它对我有帮助的话。@NFA您似乎想添加一些调试输出功能,当您不再需要它时,您希望尽可能轻松地删除这些功能。请参阅我的编辑以获取其他建议。@moooeep以您的方式,将显示为创建基,仅为一个类创建子类,并且当看到输出时,无法轻松区分它们已经创建了两个类。@Orlandolete您可以轻松地为基类的每个实例添加UUID,并将其与名称一起打印。我明白了。我在谷歌搜索时并没有真正找到我要查找的内容,所以我担心它无法以我希望的方式解决。我只是相信编译器会有这些信息,所以即使如果它正在构建基类部分,那么它将从顶层向下遍历,以便能够保留该信息。
#ifdef DEBUG
  #define PRINT_CLASSNAME std::cout<<"Creating "<<id<<std::endl;
#else
  #define PRINT_CLASSNAME ;
#endif
class Base {
public:
    std::string name() const { return typeid(*this).name(); }
};