我需要一个侵入性,有序,双链表。我不想使用boost :: intrusive,所以我自己这样做并遇到问题
对于双向链表,有几个操作,这里只是其中一个有助于说明我的观点:
template<typename LIST, typename NODE>
void insertAfter(LIST *list, NODE *node, NODE *newNode)
{
newNode->prev_ = node;
newNode->next_ = node->next_;
if(nullptr == node->next_)
list->last_ = newNode;
else
node->next_->prev_ = newNode;
node->next_ = newNode;
}
现在假设我有一组对象在一个这样的列表中但是我希望他们的内容是私有的:
struct Object
{
private:
Object *prev_, *next_;
};
现在我创建了我的列表(请忽略这样一个事实:当列表为空时会有一个nullptr异常...)。
struct List
{
Object *first_, *last_;
void addObject(Object *o)
{
insertAfter(this, last_, o); // not correct when list empty
}
};
这将无法编译,因为prev_和next_是私有的,而insertAfter没有访问权限。它可以很容易地解决:
// Fwd decl
struct List;
struct Object
{
friend void insertAfter<List, Object>(List *, Object *, Object *);
private:
Object *prev_, *next_;
};
struct List
{
Object *first_, *last_;
void addObject(Object *o)
{
insertAfter(this, last_, o);
}
};
但这会打开一个访问漏洞,任何人都可以使用insertAfter来影响Object的私有成员。我真正想要的是List成为Object的朋友。 我可以通过不使用模板进行链接列表操作来解决这个问题(使用普通的宏),但这显然有其缺点。什么是正确的方式去这里?
答案 0 :(得分:1)
这些方面的内容怎么样?
template<class ObjectType>
class List
{
ObjectType *first_, *last_;
public:
void addObject(ObjectType *o)
{
insertAfter(this, last_, o);
}
void insertAfter(ObjectType *node, ObjectType *newNode)
{
newNode->prev_ = node;
newNode->next_ = node->next_;
if(nullptr == node->next_)
this->last_ = newNode;
else
node->next_->prev_ = newNode;
node->next_ = newNode;
}
};
class Object
{
private:
Object *prev_, *next_;
friend class List<Object>;
};
int main() {}
我无法看到它比你已经做过的那样真的不那么冒犯了:模板代码无论如何都是内联的,所以你无法阻止人们根据自己的喜好重写你的课程。只需放松并对您的客户有合理的信任度:)
答案 1 :(得分:0)
您可以封装侵入性数据,例如:
template <typename Object>
class List
{
public:
class PrivateData
{
friend class List;
public: // minimal stuff which should be public go here
PrivateData() : prev_(nullptr), next_(nullptr) {}
private:
// other stuff
Object *prev_, *next_;
};
// Other stuff
};
然后在你的对象中:
class Object
{
public:
List<Object>::privateData listData_;
private:
// internal data.
};
由于ListData
中的所有内容都是私有的,因此用户无法对listData_
执行任何操作
但可以由朋友List
访问。