繁体   English   中英

在基类中打印派生类名

[英]Printing derived class name in base class

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

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

编辑:理想情况下,我正在寻找添加到基类中的东西,而无需编辑所有派生类。 目前我的真实代码已经有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

但随着编译添加前缀。

遗憾的是没有简单的解决方案。

问题是构造多态对象非常复杂,在构建Child类的Base子部分的那一刻,你仍在构建一个Base ,而不是一个Child (因为尝试访问Child成员将是非敏感的,他们有尚未建成!)

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

出于对称原因,析构函数中也会出现相同的情况。


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

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

它将工作...除非你从构造函数或析构函数调用它,在这种情况下它将报告静态类型。

现在,就“奇异”输出而言,每个实现(编译器)都允许在这里提供自己的输出(对于不同类型它们甚至不需要不同,疯狂呃!)。 你似乎在使用gcc或clang。

demanglers来解释这样的输出,或者如果你的程序很简单并且它们的界面让你害怕,你可能只是尝试手动解析它来删除这个输出。 该类的名称应该完整显示,它之前只是一些废话(名称空间和数字本质上)。

由于您指出这是用于调试,因此您可以依赖虚拟继承来避免将名称传递给所有中间派生类,而是将其直接传递给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) {}
}

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

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

我打算纯粹用于调试目的,这就是为什么投入基类会很方便的原因。

您是否考虑过在代码中添加宏来打印调试输出?

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

你需要将它添加到你的构造函数一次,但如果你想(暂时)禁用它你只是取消定义它?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM