侵入式数据结构的OO设计
OO design for intrusive data structure
我正在编写一个侵入性链表
class ListAlgorithm {
ListNode& next(ListNode& n) {
//returns an object of type ListNode linked to n.
}
};
用户通常希望在ListNode上添加一些功能(例如一些附加数据),如下所示:
class UserNode : public ListNode {
void operationOnUserData();
int userData;
};
然后,用户必须将"next"返回的ListNode向下投射到UserNode中。这很不方便。因此,我试图使ListAlgorithm成为一个模板类:
//U extends ListNode
template<class U>
class ListAlgorihtm {
U& next(U& u);
};
但是我必须将u升级到方法"next"中的ListNode中,因为类U可能会意外隐藏ListAlgorithm使用的一些ListNode成员。这很容易出错,因为我可能会忘记向上转换,编译器不会对此发出警告。对于返回值,我必须再次将 ListNode 向下投射到 U 中,但它是安全的,因为"next"需要您的实例 u,并且返回值来自 u。
另一项试验是
//U extends ListNode
template<class U>
class ListAlgorhtm {
U& next(ListNode& n);
};
在这种情况下,上播问题不存在,但我必须将 ListNode 向下投射到 U 中以获取返回值,这是不安全的,因为它不确定 n 是 U 的实例。它可能是扩展ListNode的另一种类型的实例。
在这种情况下,最好的解决方案是什么?我认为这是一个非常基本的设计问题,我想知道我必须学习什么样的材料才能进行这样的基本OO设计。
您的实际问题是,您允许用户通过子类向ListNode
对象添加任意数据和操作来子类化ListNode
并弄乱其语义。因此,这使得用户有必要将实际ListNode
方法的ListNode&
返回值解释为这些返回值在语义上不是的东西。
这个语义性质的问题反映在你的代码突然变得多么乏味上,一个不相关的类(ListAlgorithm
)的强制转换和模板化是由于你的问题"传播"和感染代码的其他部分。
这是一个解决方案:不应允许ListNode
对象也是UserNode
对象。但是,应该允许它携带一个可以检索和操作的UserData
对象。
换句话说,您的列表成为一个简单的容器模板,如 std::list
,用户可以指定他们需要的操作和数据成员,作为他们用作模板参数的类定义的一部分。
class IListNode
{
public:
// whatever public methods you want here
protected:
// pure virtual methods maybe?
};
class ListNode : public IListNode
{
// List node class, no data
};
template<class UserDataType>
class ListNodeWithData : public IListNode
{
private:
UserDataType data;
public:
ListNodeWithData <UserDataType>(UserDataType &data) :
data(data)
{ }
const UserDataType& getData() {
return data;
}
};
class ListAlgorithm
{
public:
template<class UserDataType>
ListNodeWithData<UserDataType>& next(const ListNodeWithData<UserDataType>& node) {
// Do stuff
}
ListNode& next(const ListNode& node) {
// Do stuff, which may be very similar to the stuff done above
// in which case you may want to prefer to just define the
// method below, and remove this one and the one above:
}
// You should define either this method or the two above, but having
// them all is possible too, if you find a use for it
IListNode& next(const IListNode& node) {
// Do generic stuff
}
};
就结果类的大小而言,我只知道如果你在IListNode中使用虚拟方法,它会增加。
就您提出的问题而言,任何时候您想对类的成员进行操作并避免被派生类隐藏,只需确保您的操作在基础上,所以
template<class U>
class ListAlgorihtm {
public:
U& next(U& u) {
return static_cast<U&>(return nextNode(u));
}
private:
ListNode& nextNode(ListNode& n);
};
也就是说,对于此问题集,您有很多选择。 Boost 库有一个"侵入式"库,它将节点信息嵌入为base_hook
(作为用户数据的基础)或member_hook
(作为类的成员,这避免了您描述的一些问题)。 在 http://www.boost.org/doc/libs/1_57_0/doc/html/intrusive.html 查看。
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 询问在设计我的手臂模拟器功能表示格式1
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 资源管理设计模式
- 多态杆件变量 - 类设计
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 如何使用要传递给 mt19937 的可选随机种子参数设计函数
- 设计将引用元素移动到开头的数据结构.C++
- С++ wxWidgets:代码架构,设计原则和模式
- 侵入式数据结构的OO设计
- 避免了OO设计中的RTTI
- C++如何在OO设计中显示多维数组
- c++和设计一个OO类
- 最好的OO设计实现在c++中
- c++ OO设计:模板参数的继承
- 重构建议:如何在OO设计中避免类型检查
- OO设计:多个实例但是静态回调
- C++中的OO设计-用未知类型的子对象装饰父对象