【问题标题】:Design alternative for access to derived class member from base class pointer从基类指针访问派生类成员的设计替代方案
【发布时间】:2014-02-18 16:18:34
【问题描述】:

我正在编写一个 DAL/ORM 库。该库将主要从 GUI 访问,但也从一些“业务级”应用程序访问。我仍处于这个库的设计阶段,到了不知道如何很好地解决以下问题的地步。

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

我现在希望能够执行以下所有操作:

  • 尽可能降低接口的复杂性
  • 遍历List 中的所有Properties,并调用Property 两种风格都支持的方法。
  • 当拥有Property 的实例时,以类型安全的方式访问其值
  • 如果可能,请避免使用 dynamic_cast 或类似结构

所以,显然纯多态在这里不能解决问题。我已经对奇怪地重复出现的模板模式和两个类层次结构的组合做了一些实验——一个用于Properties,一个用于它们的值(下面的示例代码)。但是,到目前为止,我还没有成功地获得满足我所有要求的设计。

基本设计(即存在哪些类、它们的组织方式等)不是固定的,可以轻松更改。我还在这个项目的设计阶段,所以只有测试代码存在。但是,基本思想必须像上面解释的那样(即List 具有Properties,而values 又具有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) {};
};

【问题讨论】:

  • 真正的问题是您希望如何访问值。您只是在 GUI 中公开它们吗?当你有一个“键”时,你知道“值”类型吗?
  • 我正在写一个 DAL/ORM。所以是的,GUI 是使用我的库的主要域。我没有真正的键值对。但是,我可以通过某种键告诉值数据类型

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


【解决方案1】:

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

遍历List 中的所有Properties,并调用Property 两种风格都支持的方法。

这是polymorphism

Properties 的两种风格都有一个基类,它有一个虚函数,你的 A 和 B Property 类会覆盖它。然后,您可以从存储在List 中的基类指针调用该函数。

【讨论】:

  • 我对多态很熟悉。但是多态性不允许我以类型安全的方式访问属性的值。请记住,它们属于不同类型。即使是相同风格的属性也可以有不同的值类型。
  • @sigy:很公平,你能给我们举一个你的Property 的例子吗(我假设是Class?)。你能让你的Property 类有点像Variant data type 吗?
【解决方案2】:

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

现在看来,这种方法满足了我最初的所有要求:

  • 它使界面的复杂性保持在低水平✓
  • 遍历List 中的所有Properties,并通过使用std::for_eachboost::apply_visitor 调用Property 支持的方法 ✓
  • 当拥有Property 的实例时,如果我的Property 基类允许访问其ValueType 成员,则可以以类型安全的方式访问其值。 ✓
  • 不需要使用 dynamic_cast 或类似结构 ✓

仍然感谢任何采用这种方法的 cmets。

【讨论】:

    猜你喜欢
    • 2011-01-27
    • 2016-07-31
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多