从基类指针访问派生类成员的设计方案 [英] Design alternative for access to derived class member from base class pointer
问题描述
在我目前的设计中有一个类,让我们称之为 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
inList
, and call methods that bothProperty
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
inList
, and calling methods that bothProperty
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 myProperty
base class gives access to itsValueType
member. ✓ - Use of dynamic_cast or similar constructs is not needed ✓
Any comments on this approach are still appreciated.
这篇关于从基类指针访问派生类成员的设计方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!