在基类中打印派生类名
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。
有 demangler 来解释这样的输出,或者如果你的程序足够简单并且它们的界面让你害怕,你可以简单地尝试手动解析它以去除麻烦。类的名称应该完整地出现,它前面只是一些废话(本质上是命名空间和数字)。
你可以提供一个需要从每个构造函数调用的初始化函数。
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
您需要将其添加到构造函数中一次,但是如果您想(暂时)禁用它,只需取消定义它?
由于您指示这是用于调试的,因此您可以依靠虚拟继承来避免通过所有中间派生类传递名称,而是将其直接传递给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) {}
}
- 如何循环打印顶点结构
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 如何在c++中打印目录
- 在派生函数中指定void*参数
- 如何通过派生类函数更改基类中的向量
- 如何委托派生类使用其父构造函数?
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 在线编译器中的分段C++没有打印消息
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 通过基类引用派生类后打印的错误值
- C++ - 打印派生类对象的矢量<base*> 元素
- C++ 打印从字符串字符派生的整数
- 在基类中打印派生类名
- 使用引用此对象的基类指针向量打印派生类对象
- 从具有基类函数的派生类打印
- C++ 指针向量<base_class*>放置派生类但切片打印
- 给定一个基类作为参数,如果传递了一个派生类的特征,如何使用 op<< 重载来打印派生类的特征?