类的层次结构描述了某个对象的不同属性。抽象类 Property
是一个基类,它有子类:IntegerProperty
、BooleanProperty
等。所有数据都在 QString
中编码,派生类以自己的方式对其进行解码。
class Property : public QObject
{
Q_OBJECT
public:
// ...
virtual QString value() const = 0;
virtual bool setValue(const QString &value) = 0;
virtual bool validateValue(const QString& value) = 0;
// ...
};
class IntegerProperty : public Property
{
// ...
virtual QString value() const override;
virtual bool setValue(const QString &value) override;
virtual bool validateValue(const QString& value) override;
// ...
};
// ...
每个属性类都必须有一个独立的编辑器(GUI 小部件)- PropertyEditor
(又是抽象类)、IntegerPropertyEditor
、BooleanPropertyEditor
等等在。
class PropertyEditor : public QWidget
{
Q_OBJECT
public:
inline Facer::PropertyPointer attachedProperty() { return m_property; }
protected:
PropertyEditor(Facer::PropertyPointer attachedProperty, QWidget* parent = nullptr);
virtual void mousePressEvent(QMouseEvent* event) override;
virtual bool eventFilter(QObject *watched, QEvent *event) override;
// ...
};
class IntegerPropertyEditor : public PropertyEditor
{
// ...
};
// ...
例如,我有一组不同的属性。我不知道我到底有哪些属性,因为它们都是指向 Property
类的指针。我的任务是为这些属性创建指定的编辑器,因此如果属性对象是 IntegerProperty
,我需要获取 IntegerPropertyEditor
。
for (Property* property : propertySet())
PropertyEditor* editor = createEditor(property);
我用宏做了一个临时的解决方法:
#define IF_TYPE_GET_EDITOR(propertyType, editorType) \
if (std::dynamic_pointer_cast<propertyType>(property)) \
return new editorType(property, this);
// ...
PropertyEditor *PropertySetWidget::create(PropertyPointer property)
{
IF_TYPE_GET_EDITOR(BooleanProperty, BooleanPropertyEditor)
else IF_TYPE_GET_EDITOR(ColorProperty, ColorPropertyEditor)
else IF_TYPE_GET_EDITOR(FloatingPointProperty, FloatingPointPropertyEditor)
else IF_TYPE_GET_EDITOR(FontProperty, FontPropertyEditor)
else IF_TYPE_GET_EDITOR(IntegerProperty, IntegerPropertyEditor)
else IF_TYPE_GET_EDITOR(TextProperty, TextPropertyEditor)
else throw std::runtime_error("This PropertyType is not implemented yet");
}
这看起来不是一个好的解决方案 - 如果我添加一种新类型的属性及其编辑器,我也必须更新此代码。链接编辑器类和属性类的最方便和通用的方法是什么?
最佳答案
这可能会提供一些额外的代码,特别是取决于您的项目是如何设置的,但一种解决方案是在 Property
中创建一个返回指向编辑器指针的虚函数:
class Property : public QObject
{
public:
virtual PropertyEditor* CreateEditor(PropertySetWidget* widget) {
// let's put our default behavior here
throw std::runtime_error("This PropertyType is not implemented yet");
}
//...
};
现在,您让每个类负责提供自己的编辑器:
class IntegerProperty : public Property
{
public:
// doesn't have to be virtual, I don't think Just a regular version should be fine too.
virtual PropertyEditor* CreateEditor(PropertySetWidget* widget) {
return new IntegerPropertyEditor(this, widget);
}
//...
};
根据您拥有的类(class)数量,可能需要进行大量复制和粘贴操作。
然而,有趣的部分是 PropertySetWidget::create()
:
PropertyEditor *PropertySetWidget::create(PropertyPointer property)
{
return property->CreateEditor(this);
}
因为 property
的每个 child 都负责提供自己的编辑器,所以我们不必在这个级别上担心它。如果不存在/未实现,property::CreateEditor()
将为您抛出错误。如果确实存在/已实现,它将自动向编辑器返回一个指向新实例的指针。
最大的好处是,如果你添加一个新的属性和它的编辑器,你根本不必去触及它这个功能。虚函数负责为您正确实现它。如果新属性有一个编辑器,它只需要重载那个函数,这个 create()
仍然可以正常工作。
当然,您将不得不以这种方式修改Property
的接口(interface),这在您的情况下可能不可行。这是这种方法的主要缺点。
关于c++ - 在没有额外代码的情况下链接两个独立类的最通用方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57386576/