有一个类层次结构,描述了某个对象的不同属性。抽象类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
类的指针。我的任务是为这些属性创建指定的编辑器,因此我需要获取IntegerPropertyEditor
属性对象是否为IntegerProperty
。
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");
}
它看起来不是一个很好的解决方案-如果我添加一种新类型的属性及其编辑器,则也必须更新此代码。链接编辑器类和属性类的最方便,最通用的方法是什么?
您想要的东西需要实现反射,尽管没有宏就可以通过笨拙的方式实现想要的东西。我个人推荐@Chipster的解决方案。
如果您仍然对不需要Property提供其自己的编辑器的方法感兴趣...我编写了一个示例,您可以查看一下。
#include <iostream>
#include <memory>
class A
{ //virtual working class
public:
virtual ~A() = default;
};
//two possible implementations
class B : public A {};
class C : public A {};
//Editor interface
class EditorA
{
public:
virtual ~EditorA() = default;
virtual void print() = 0;
};
//Implementations of editors
class EditorB :
public EditorA
{
public:
void print() override
{
std::cout << "Editor B\n";
}
};
class EditorC :
public EditorA
{
public:
void print() override
{
std::cout << "Editor C\n";
}
};
//template class used for declaring which Editor you use depending on the class you provide
// I would make a namespace but there are no template namespaces
template<typename T>
class EditorT;
template<>
class EditorT<B>
{
public:
using EditorType = EditorB;
};
template<>
class EditorT<C>
{
public:
using EditorType = EditorC;
};
using namespace std;
// Recursive GetEditor code... written inside class as a static method for reasons.
template<typename... Args>
class CEditorIdentifier;
template<>
class CEditorIdentifier<>
{
public:
static EditorA * GetEditor(shared_ptr<A>& val)
{
return nullptr;
}
};
template<typename Arg, typename... Args>
class CEditorIdentifier<Arg, Args...>
{
public:
static EditorA * GetEditor(shared_ptr<A>& val)
{
if(std::dynamic_pointer_cast<Arg>(val))
{
return new typename EditorT<Arg>::EditorType;
}
return CEditorIdentifier<Args...>::GetEditor(val);
}
};
template<typename... Args>
EditorA* FindEditor(shared_ptr<A>& val)
{
return CEditorIdentifier<Args...>::GetEditor(val);
}
int main()
{
shared_ptr<A> b = make_shared<B>();
shared_ptr<A> c = make_shared<C>();
EditorA* eB = FindEditor<B,C>(b);
EditorA* eC = FindEditor<C,B>(c);
eB->print();
eC->print();
return 0;
}
现在,您可以添加额外的课程D
,E
,F
...你只需要保持引用类EditorT<D>
,EditorT<E>
,EditorT<F>
...
复杂吧?好吧... C ++中用于此类编程的当前功能是有限的。它正在工作,将来会可用(请参阅Reflection TS),但现在不可用。同样,使用C ++ 20的所有扩展也将更容易实现constexpr
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句