从基类指针访问派生类成员的设计方案 [英] Design alternative for access to derived class member from base class pointer

查看:671
本文介绍了从基类指针访问派生类成员的设计方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个DAL / ORM库。该图书馆将主要从GUI访问,也可以从某些业务级应用程序访问。我仍然在这个图书馆的设计阶段,而且我不知道如何很好地解决以下问题。



在我目前的设计中有一个类,让我们称之为 List ,其中有一个容器是另一个类,属性。属性有两种口味(A和B),主要具有相同的功能,但其一些功能是不同的。此外,$ 属性的两种口味都存储值。值可以是不同的数据类型,包括但不限于POD。每个列表可以只包含一个属性一次,属性我们现在希望能够执行以下所有操作:




  • 保持界面的复杂性尽可能低

  • 迭代所有属性列表中,并调用 Property flavor支持的方法。

  • 具有属性的实例,以类型安全的方式访问其值

  • 如果可能,避免 dynamic_cast 或类似的构造



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



基本设计(即哪些类,如何组织等等)不固定,可以轻松更换。我仍然在这个项目的设计阶段,所以只有测试代码存在。然而,基本思想必须像上面所解释的那样(即,一个列表具有属性,而<$ code>



非常感谢任何我的问题或原始想法,想法等的解决方案。






层次结构实现的示例代码。显然,我将无法以类型安全的方式访问该物业的价值。

  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)];返回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){};
};


解决方案

我终于决定使用 boost :: variant 在我的列表 class。我的属性类现在是一个模板类,其中模板参数用 ValueType 类的子类实例化。 属性的不同口味来源于属性类。



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




  • 它使界面的复杂度保持不变✓

  • 迭代列表中的所有属性,并调用属性可以使用 std :: for_each boost :: apply_visitor

  • 当具有 Property 的实例时,如果我的属性基类允许访问其 ValueType 成员。 ✓

  • 不需要使用dynamic_cast或类似结构✓



对此方法的任何评论仍然赞赏。


I'm writing a DAL/ORM library. This library will be accessed mainly from GUIs but also from some "business level" applications. I'm still in the design phase of this library and came to a point where I'm not sure how to solve the following issue nicely.

In my current design I have a class, let's call it List for the moment, that has a container of another class, Properties. Properties come in two flavors (A and B), with mostly the same functionality, but some of their functionality is different. Furthermore both flavors of Properties store values. Values can be of different data types, including, but not limited to, PODs. Each List can contain a certain Property only once and Properties are identified by a "name", i.e. a string.

I now want to be able to do all of the following:

  • Keep the complexity of the interface as low as possible
  • Iterate over all Properties in List, and call methods that both Property flavors support.
  • When having an instance of a Property, accessing its value in a type safe way
  • If possible, avoid dynamic_cast or similar constructs

So, obviously pure polymorphism cannot do the trick here. I have done some experiments with the curiously recurring template pattern and with composition of two class hierarchies - one for Properties and one for their values (example code below). However, so far I did not succeed in getting a design that fulfilled all my requirements.

The basic design (i.e. which classes exist, how they are organized etc.) is not fixed and could be easily changed. I am still in the design phase of this project, so only test code exists. However, the basic idea has to bee like explained above (i.e. that a List has Properties which in turn have values).

Any solutions to my problems or raw ideas, thoughts, etc. are highly appreciated.


Example code for hierarchy implementation. Obviously I will not be able to access a property's value in a type-safe way here.

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) {};
};

解决方案

I finally decided to use a vector of boost::variant in my List class. My Property class is now a template class where the template parameter is instantiated with subclasses of a ValueType class. The different flavors of Properties derive from the Property class.

Right now it seems that this approach fulfills all my initial requirements:

  • It keeps the complexity of the interface low ✓
  • Iterating over all Properties in List, and calling methods that both Property flavors support is possible by using std::for_each and boost::apply_visitor
  • When having an instance of a Property, accessing its value in a type safe way is possible if my Property base class gives access to its ValueType member. ✓
  • Use of dynamic_cast or similar constructs is not needed ✓

Any comments on this approach are still appreciated.

这篇关于从基类指针访问派生类成员的设计方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆