【问题标题】:How can I make 2 c++ classes know about each other's data members?如何让 2 个 c++ 类知道彼此的数据成员?
【发布时间】:2012-07-17 16:20:57
【问题描述】:

我的任务是创建一个类似于标准库List 的类。我无法让迭代器正常工作,因为它必须在从末尾递减时访问链表的尾部。这是我的头文件的一部分:

typedef int T;//for now; eventually will be templated
class list;//**forward declaration, doesn't let other classes know about _tail.**
class Node
{
    //this works fine; class definition removed to make post shorter
};
class list_iterator
{
    private:
        Node* _node;
        list* _list;
    public:
        //constructor
        list_iterator& operator--(){_node=_node?(_node->_prev):(_list->_tail);return *this;}
        //some other declarations
};
class list
{
    friend class list_iterator;
    private:
        Node/*<T>*/ *_head,***_tail**;
        int _size;
    public:
        typedef list_iterator iterator;
        //some constructors and other method declarations
        iterator begin() const {iterator it(_head);return it;}
        iterator end() const {iterator it(0);return it;}
        //more method declarations
};

我尝试将重要部分加粗,但它只是用星号围绕它们。 注意:大部分成员函数都定义在 cpp 文件中;他们都碰巧因为一个简短的帖子而被删除。

【问题讨论】:

  • 你在这里给出的函数实现叫做inline。您应该了解这对编译器意味着什么,以便您可以继续正确使用它。
  • 至于粗体格式...看起来你放了太多星号。 Bold 只需要其中两个。如果这不起作用,请尝试在前两个星号之前和最后两个星号之后添加空格。 (事实上​​,您的代码格式通常可以通过一些适当的空格来改进。)
  • 我想强调其中一个指针。原来这个功能被拒绝了(在代码中转义粗体) - meta.stackexchange.com/questions/32705/bold-code-in-a-question
  • 抱歉,我遇到了解析错误。我错过了额外的 * 用于指针声明。另外,感谢您的链接。

标签: c++ class iterator datamember


【解决方案1】:

您只需将operator-- 的方法定义移出类并将其放在列表之后(或放在源文件中(可能更好。保留头文件进行声明)。

注意:将声明保留在 list_iterator 中

class list_iterator
{
    /* STUFF */
    list_iterator& operator--();
 };
class list
{ 
     /*  STUFF */ 
};

// Now list_iterator::operator-- can see all the members of list.
list_iterator& list_iterator::operator--()
{
    _node=_node?(_node->_prev):(_list->_tail);
    return *this;
}

与其他一些答案所暗示的不同。 Friendship does NOT break encapsulation。事实上,通过使友元成为类接口的一部分来增加封装(正确完成时)。然而,它确实将朋友与班级紧密地联系在一起。

这正是您想要的迭代器。为了让迭代器有效地工作,它需要知道类的内部结构,所以它通常是一个朋友(或一个内部类)。它增加了类的可用性而不暴露类的内部工作,代价是它将迭代器与类紧密耦合(因此,如果您更改类,您将需要更改迭代器的实现(但这并不意外))。

【讨论】:

  • 一般来说,像这个例子一样将函数实现与类声明分开是一个好主意(TM)。
  • @Code-Guru:虽然我原则上同意这个建议太笼统了。实际的实地实践将根据情况量身定制。
  • 我同意我之前的建议过于笼统。补充一点,应该了解内联函数和非内联函数之间的区别,并选择最合适的方法。在这种特殊情况下,了解声明和定义之间的区别对于修复编译器错误也很重要。
【解决方案2】:

到目前为止,最简单的方法是将迭代器嵌套在列表类中:

class list { 
    Node *head, *tail;

    class iterator {
        Node *node;
        list *list;
    // ...
    };
};

如果您不想这样做,则需要将 listlist_iterator 的实现分成两部分:首先是只声明成员函数的类定义,然后是成员的实现功能:

class list;

class list_iterator { 
    // ...
    Node *n;
    list *l;
};

class list {
    // ...
    friend class list_iterator;
};

inline list_iterator& list_iterator::operator--(){
    _node=_node?(_node->_prev):(_list->_tail);
    return *this;
}

这样,当您在list_iterator 的定义中定义list * 时,已经声明了list。那么_tail已经在list中定义了,那么你在list_iterator::operator--中就有了实际需要使用list::_tail的代码..

【讨论】:

  • 是朋友,只是事先定义好的。
  • @Jake:您只需将方法定义operator-- 移出类即可。并将其放在list 之后。注意:将声明留在list_iterator
  • 给出答案,我会接受(假设没有更好的结果)。
  • @Jake223:明显的好处包括简单和没有名称污染。不嵌套可以让你做SCARY iterators,这很方便,但可能远远超出你期望为你的作业处理的内容(事实上,除非你的课程包括相当多的你,否则根本不要申请'没有显示)。
  • @Jake223 这些备选方案相互排斥。即使使用嵌套类,您通常仍应在单独的 .cpp 文件中定义方法。正如我在上面所评论的,您编写代码和分离 .h 和 .cpp 文件的方式之间的区别与 内联函数 有关。嵌套类的替代方法是使用原始代码中的友元类。 (同样可以使用单独的 .cpp 文件。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-19
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多