我正在尝试创建一个像Java swing
这样的系统,你有一个窗口,那个窗口有多个组件,比如标签(文本/图像),文本框,复选框等。 swing
的工作原理是有一个Component
类,它是抽象的,它有一个抽象绘制方法,它绘制组件和其他一些方法。实际窗口(JFrame
)具有窗口中所有组件的列表(各种)。这些组件的实际类型是未知的,但它们都扩展了Component
类。
我的Window
课程:
class Window {
public:
...
template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr> T addComponent(T component);
private:
...
std::vector<Component> components;
...
};
Component
:
class Component {
public:
...
virtual void paintComponent() = 0;
...
};
在该行的某处,此代码称为:
for each (Component c in components) {
c.paintComponent();
}
但是,我不能创建Component
类型的对象,因为它是抽象的,尽管实际的对象是其他类型的 extends Component
并拥有自己的{ {1}}方法。对于方法(paintComponent()
),我可以使用
Window::addComponent()
但是,这对变量不起作用。
所以,我的问题是,如何创建抽象类型的对象,即如何创建template<typename T, typename std::enable_if<std::is_base_of<Component, T>::value>::type* = nullptr> T
对象(或扩展Component的对象,但实际的类型未知)?
提前致谢!
答案 0 :(得分:5)
您无法实例化抽象类的类型。你必须通过指针来引用它。这将迫使您进行手动内存管理。因此,使用shared_ptr
或unique_ptr
等智能指针可以帮助减轻头痛。使用指针会使你的矢量看起来像这样
std::vector<Component*> components;
// ^ Indicates pointer
然后在你的循环中你会像这样称呼它
p->paintComponent();
这样,您可以将Component
用于从中派生的任何类型。
此外,如果要像这样使用Component,它应该有一个虚拟析构函数。这将确保在通过指向Component
的指针删除时调用正确的析构函数。这会使析构函数声明看起来像这样
virtual ~Component() { }
答案 1 :(得分:1)
在类似的系统中, Label , CheckBox , TextBox 等类型是从 Component 类派生的单独类。因此,如果您想要类似的行为,则需要实现新类并从 Component 类派生它们。您还需要覆盖虚拟功能。