设计从基类指针访问派生类成员的替代方法

时间:2014-02-18 16:18:35

标签: c++ design-patterns inheritance derived-class crtp

我正在写一个DAL / ORM库。该库主要从GUI访问,但也可以从一些“业务级”应用程序访问。我还处在这个库的设计阶段,并且我不确定如何很好地解决以下问题。

在我目前的设计中,我有一个类,我们暂时称它为List,它有另一个类的容器Properties。属性有两种类型(A和B),大多数功能相同,但它们的一些功能不同。此外,Properties两种风格都存储了价值。值可以是不同的数据类型,包括但不限于POD。每个List只能包含一次PropertyProperties只能通过“名称”标识,即字符串。

我现在希望能够做到以下所有事情:

  • 尽可能降低界面的复杂性
  • Properties中的所有List进行迭代,并调用Property种口味支持的方法。
  • 拥有Property的实例时,以类型安全的方式访问其值
  • 如果可能,请避免使用dynamic_cast或类似的构造

所以,显然纯粹的多态性不能在这里做到。我已经使用奇怪的重复模板模式和两个类层次结构的组合进行了一些实验 - 一个用于Properties,另一个用于它们的值(下面的示例代码) 。但是,到目前为止,我没有成功地完成满足我所有要求的设计。

基本设计(即存在哪些类,它们如何组织等)不是固定的,可以很容易地改变。我仍处于该项目的设计阶段,因此只存在测试代码。但是,基本思想必须如上所述(即ListProperties,而values又有class PropertyValue { public: virtual std::string GetAsString() const = 0; bool IsReadOnly() const { return m_isReadOnly; } void IsReadOnly(const bool val) { m_isReadOnly = val; } protected: PropertyValue(PropertyValue & other) : m_isReadOnly(other.m_isReadOnly) {}; PropertyValue(bool readOnly) : m_isReadOnly(readOnly) {}; private: bool m_isReadOnly; }; class StringValue : public PropertyValue { private: typedef std::string inner_type; public: StringValue(const inner_type & value, bool readOnly) : PropertyValue(readOnly) , m_value(value) {}; StringValue(StringValue & other) : PropertyValue(other.IsReadOnly()) , m_value(other.m_value) {}; std::string GetAsString() const { return m_value; }; inner_type GetValue() const { return m_value; }; void SetValue(const inner_type & value) { m_value = value; }; unsigned int GetMaxLenght() const { return m_maxLength; }; private: inner_type m_value; unsigned int m_maxLength; }; class IntValue : public PropertyValue { private: typedef int inner_type; public: IntValue(const inner_type & value, bool readOnly) : PropertyValue(readOnly) , m_value(value) {}; IntValue(IntValue & other) : PropertyValue(other.IsReadOnly()) , m_value(other.m_value) {}; std::string GetAsString() const { char tmp[((CHAR_BIT * sizeof(int)) / 3 + 1)]; return itoa(m_value, tmp, 10); }; inner_type GetValue() const { return m_value; }; void SetValue(const inner_type & value) { m_value = value; }; int GetMinValue() const { return m_minValue; }; int GetMaxValue() const { return m_maxValue; }; private: inner_type m_value; int m_minValue; int m_maxValue; }; class Property { public: Property(std::auto_ptr<PropertyValue> value, bool visible) { m_value = value; m_isVisible = visible; } bool IsVisible() const { return m_isVisible; } void IsVisible(const bool val) { m_isVisible = val; } std::string GetValueAsString() const { return m_value->GetAsString(); }; const PropertyValue & getValue() const { return (*m_value.get()); } private: std::auto_ptr<PropertyValue> m_value; bool m_isVisible; }; class PropertyFlavorA : public Property { public: PropertyFlavorA(std::auto_ptr<PropertyValue> value, bool visible) : Property(value, visible) { value->IsReadOnly(true); }; }; class PropertyFlavorB : public Property { public: PropertyFlavorB(std::auto_ptr<PropertyValue> value, bool visible) : Property(value, visible) {}; };

我的问题或原创想法,想法等的任何解决方案都受到高度赞赏。


层次结构实现的示例代码。显然,我不能在这里以类型安全的方式访问属性的值。

{{1}}

2 个答案:

答案 0 :(得分:1)

您似乎已回答了自己的问题......

  

Properties中的所有List进行迭代,并调用Property种口味支持的方法。

这是polymorphism

Properties的两种口味都有一个基类,它有一个虚拟函数,你的A和B Property类覆盖它们。然后,您可以从存储在List

中的基类指针调用该函数

答案 1 :(得分:0)

我最终决定在我的List课程中使用boost::variant的向量。我的Property类现在是一个模板类,其中模板参数使用ValueType类的子类进行实例化。 Properties的不同风格来自Property类。

现在看来这种方法符合我的所有初始要求:

  • 它使界面的复杂性降低✓
  • Properties中的所有List进行迭代,并使用std::for_eachboost::apply_visitor调用Property种口味支持的方法✓
  • 当拥有Property的实例时,如果我的Property基类可以访问其ValueType成员,则可以以类型安全的方式访问其值。 ✓
  • 不需要使用dynamic_cast或类似构造✓

对这种方法的任何评论仍然受到赞赏。