繁体   English   中英

C ++如何通过自制的侵入式列表避免使用朋友模板函数

[英]C++ How to avoid friend template functions with home-made intrusive lists

我需要一个侵入式,已排序的双向链接列表。 我不想使用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的朋友。 我可以通过不在链接列表操作中使用模板来解决此问题(改为使用普通宏),但这显然有其缺点。 去这里的正确方法是什么?

沿着这些思路怎么样?

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

不过,我看不出它的冒犯程度实际上不如您以前做的那么好:模板代码仍然是内联的,因此您不能阻止人们按照自己的喜好重写类。 放松一下,对客户保持合理的信任度:)

您可以封装侵入性数据,例如:

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访问。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM