指向嵌套类的指针的加法操作符重载

Addition operator overload for pointers to nested classes

本文关键字:操作符 重载 指针 嵌套      更新时间:2023-10-16

我正在研究一个包含私有嵌套节点类的链表类。我想通过使用重载的加法运算符在我的列表中向前推进n个节点,但clang给了我错误"重载'运算符+'必须是一元或二元运算符(有3个参数)"。我认为当您将隐含的this形参声明为友元函数时,它就消失了。

首先是头文件

 template <class T>
 class List
    {
  private:
    class ListNode
    {
      public:
        ListNode();

        ListNode(const T& ndata);

        friend ListNode* operator+(const ListNode* &node, int n);
        ListNode* next;
        ListNode* prev;
    };
  public:
    friend ListNode* operator+(const ListNode* &node, int n);

,我的实现如下:

template <class T>
typename List<T>::ListNode* List<T>::ListNode::operator+(const ListNode* &node, int n)
{
    ListNode* current = node;
    while (n--){
        if (current->next != 0)
            current = current->next;
    }
    return current;
}

从根本上说,你试图做的事情的问题是它在指针上重载操作符。这是有问题的。尽可能简化您的代码,以下代码不会生成:

class foo{};
foo *operator+(foo *, int) {
    return nullptr;
}
int main() {}

尝试给出:

$ g++ gl.cpp 
gl.cpp:5:26: error: ‘foo* operator+(foo*, int)’ must have an argument of class or enumerated type
 foo *operator+(foo *, int) {

如果您确实想使用operator+,最简单的方法可能是使用成员操作符形式:

template<class T>
class List {
    class ListNode {        ...
    public:
        ListNode &operator+(int n) {
            ListNode *current = this;
            while (n--)
               if (current->next != 0)
                   current = current->next;
           return *current;
        }
    };
    ...
};

然而,这有点误导,因为您实际上并没有向节点添加整数,而是获得下一个节点。next方法可能更清楚:

template<class T>
class List {
    class ListNode {        ...
    public:
        ListNode *next(int n) {
            ListNode *current = this;
            while (n--)
                if (current->next != 0)
                   current = current->next;
            return current;
        }
    };
    ...
};

如前所述,指针上的操作符重载是有问题的,同样,最简单的方法是将operator+设置为成员函数。但是,有一种方法可以获得您想要的行为…

技巧是将指针包装在一个类似指针的对象中(通常称为迭代器)。

一个演示的工作示例:

class List {
    struct Node {
        Node* next; int data;
    };
    Node* m_head{0};
public:
    // the fake pointer type.
    struct Iter {
        Iter(Node* initial = 0)
            : m_base(initial) {}
        Node* operator->()
        { return m_base; }
        bool operator!=(const Iter& other) const
        { return m_base != other.m_base; }
    private:
        Node* m_base;
    };
    // get head as fake pointer.
    Iter head()
    { return m_head; }
    void push_front(const int&);
};
void List::push_front(const int& x)
{
    Node* n = new Node;
    n->data = x;
    n->next = m_head; m_head = n;
}
// non-member operator.
List::Iter operator+(List::Iter i, int count)
{
    for ( ; count > 0 && i != 0; count-- )
        i = i->next;
    return i;
}
int main(int argc, char* argv[])
{
    List list;
    for ( int i = 0; i < 10; i++ )
        list.push_front(i);
    for ( auto i = list.head(); i != 0; i = i+1 )
        std::cout << i->data << ' ';
    std::cout << std::endl;
    return 0;
}