如何从基类中打印出派生类名,而不必将构造函数一直关闭。换句话说,是否可以在基类中严格执行此操作而不在每个派生类中添加代码?
这是我得到的一个例子,如果有一种方法我想摆脱构造函数链接。
修改 理想情况下,我正在寻找要添加到基类中的东西,而不必编辑所有派生类。目前我的真实代码已经有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
但是添加了编译后缀。
答案 0 :(得分:9)
遗憾的是,没有简单的解决方案。
问题在于构建多态对象非常复杂,在构建Base
类的Child
子部分时,您正在构建Base
,而不是Child
{1}}(因为尝试访问Child
成员是非感性的,它们还没有建成!)
因此,检索动态信息的所有方法(称为RTTI或运行时类型信息)都是自动锁定以防止出现此类错误。
出于对称原因,析构函数中也会出现相同的情况。
现在,只有构造函数和析构函数被锁定,因此您可以完全拥有一个name()
方法,该方法可以高兴地返回所有实例的动态类型的 true 名称其他情况:
class Base {
public:
std::string name() const { return typeid(*this).name(); }
};
它将起作用...除非你从构造函数或析构函数中调用它,否则它将报告静态类型。
现在,就“奇异”输出而言,每个实现(编译器)都允许在这里提供自己的输出(对于不同的类型它们甚至不需要不同,疯狂呃!)。你似乎在使用gcc或clang。
有 demanglers 来解释这样的输出,或者如果你的程序足够简单并且它们的界面让你害怕,你可能只是尝试手动解析它来删除这个输出。该类的名称应该完整显示,它前面只有一些废话(主要是名称空间和数字)。
答案 1 :(得分: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) {}
}
答案 2 :(得分: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
我打算将它纯粹用于调试目的,这就是为什么投入基类会很方便。
您是否考虑过在代码中添加一个宏来打印调试输出?
#ifdef DEBUG
#define PRINT_CLASSNAME std::cout<<"Creating "<<id<<std::endl;
#else
#define PRINT_CLASSNAME ;
#endif
您需要将其添加到构造函数一次,但如果要暂时禁用它(暂时),您只需将其取消定义吗?