无法在 C++ 中将私有成员直接从 main 传递到函数

Can't pass private member directly from main to function in C++

提问人:Kevinkun 提问时间:7/22/2021 更新时间:7/22/2021 访问量:129

问:

这是我的C++代码:

#include <iostream>

class Node
{
public:
    int data;
    Node* prev;
    Node* next;
};

class Doublyll
{
private:
    Node* head;
    Node* tail;
public:
    Doublyll();
    Doublyll(int A[], int num);
    ~Doublyll();

    friend std::ostream& operator<<(std::ostream& os, const Doublyll& src);
    int Length(Node* p);
};

// Default Constructor will SET head and tail to NULL
Doublyll::Doublyll()
    : head(NULL), tail(NULL)
{
}

// Explicit Construcor
Doublyll::Doublyll(int A[], int num)
    : head(NULL), tail(NULL)
{
    // std::cout << "Explicit Constructor called!\n";

    Node** p = &head;

    for (int i = 0; i < num; i++)
    {
        Node* t = new Node;
        t->data = A[i];
        if (head == NULL)
            t->prev = NULL;
        else
            t->prev = tail;     
        t->next = NULL;

        *p = t;
        p = &(t->next);

        tail = t;
    }
}

// Destructor
Doublyll::~Doublyll()
{
    // std::cout << "Desctructor called!\n";

    Node* p = head;
    Node* tmp;

    while (p != NULL)
    {
        tmp = p;
        p = p->next;
        delete tmp;
    }
}  

// Display using Overloading << Operator
std::ostream& operator<<(std::ostream& os, const Doublyll& src)
{
    Node* tmp;
    for (tmp = src.head; tmp != NULL; tmp = tmp->next)
        std::cout << tmp->data << " ";
    std::cout << std::endl; 

    return os;   
}

// Find Length how much Node in linked list
int Doublyll::Length(Node* p)
{
    static int count = 0;

    if (p != NULL)
    {
        count++;
        Length(p = p->next);
    }

    return count;
}

int main()
{
    int A[] = {2, 4, 6, 8, 10, 12, 14};
    int size = sizeof(A) / sizeof(A[0]);

    // Create object and linked list
    Doublyll l1(A, size);
    
    // Display linked list
    std::cout << l1;

    // Get length of linked list
    int c = l1.Length(l1.head);
    std::cout << c << std::endl;

    return 0;
}

正如你所看到的,我尝试练习双倍链表。然后,我想计算链表中的节点总数。

你可以在 I try to count it using Recursion 中看到。只是因为我想用递归来练习它。但是,在我的某种方式中,这段代码:说“头部无法访问”int Doublyll::Length(Node* p)main()int c = l1.Length(l1.head);

我知道这是因为 Head 在我的 Doublyll 班上是私人的。我可以简单地将其更改为公共。或者我可以编写一个函数,该函数将返回 Head 指针,然后将其作为参数传递。getHead()

那么,有没有办法在不将成员更改为公共或编写函数的情况下将其从 my 直接传递?或者也许有另一种方法可以根据我的问题编写递归,将来也可以将其实现到另一个递归中,例如?因为如果一切都在类内,似乎很难访问。main()getHead()display()

也许你也可以回顾一下我是如何创建一个双重链表的。谢谢!

C++ 链表

评论

0赞 0x5453 7/22/2021
static int count = 0; - static函数中的变量仅在第一次调用函数时初始化,因此如果第二次调用,这将给出不正确的结果。Length

答:

4赞 Kevin 7/22/2021 #1

创建一个私有成员函数,并添加一个不带参数的公共成员,并且执行以下操作:int Doublyll::Length(Node *p)int Doublyll::Length()

int Doublyll::Length()
{
    return Length(head);
}

(此外,您可能应该使它们都保持常量 - 因为它们不应该修改任何内容)int Doublyll::Length() const

然后只需调用main即可。l1.Length()

用户不应该知道类的内部结构,并且从某个对象甚至可能不拥有的节点中询问对象的长度是没有意义的。设为私有可以防止诸如 .DoublyllDoublyllLength(Node *p)l1.Length(l2.head)

至于你的实现,这是错误的。正如评论中提到的,您正在使用 a 来跟踪长度,如果您多次调用该函数,这将为您提供错误的答案。另外,你的递归是错误的,因为你没有使用递归调用的结果。改为执行类似操作:int Doublyll::Length(node *p)static int count

int Doublyll::Length(Node *p) const
{
    // Base case - no nodes
    if (p == nullptr)
        return 0;
    // Recursive case
    return 1 + Length(p->next);
}

或者允许尾部调用优化的解决方案:

int Doublyll::Length(Node *p, int count) const
{
    // Base case - no more nodes - return count
    if (p == nullptr)
        return count;
    // Recursive case - increment count and go to the next node
    return Length(p->next, count+1);
}
int Doublyll::Length() const
{
    return Length(head, 0);
}

评论

0赞 Kevinkun 7/22/2021
那么,将函数放在 private 中实际上是“可以”的吗?而且我还可以私下放置另一个递归函数?
0赞 Kevinkun 7/22/2021
有没有我应该把函数放在 private 中的情况?
0赞 Kevin 7/22/2021
“私有”适用于不应直接向类用户公开的任何内容。你可以把任何你想要的东西放进去。
0赞 Kevinkun 7/22/2021
谢谢你的解释。这真的很有帮助!
2赞 effect 7/22/2021 #2

实现递归函数时,一种常见的技术是使用一个公共非递归函数来启动事情(例如,),以及另一个实际执行递归的私有帮助程序函数(类似于 )。Doublyll::Length()Doublyll::LengthRecursive()

这可能看起来像这样:

int Doublyll::LengthRecursive(Node* p)
{
    static int count = 0;

    if (p != NULL)
    {
        count++;
        Length(p = p->next);
    }

    return count;
}

int Doublyll::Length()
{
    return LengthRecursive(head);
}

评论

0赞 Kevinkun 7/22/2021
谢谢!这是帮助!
2赞 jwezorek 7/22/2021 #3

处理此类情况的一种方法是使用两个成员函数:一个是公共接口,另一个是私有的,但具有递归调用所需的签名。

例如:

class Doublyll
{
private:
    Node* head;
    Node* tail;

    int LengthAux(Node* p); //private recursive implementation

public:
    Doublyll();
    Doublyll(int A[], int num);
    ~Doublyll();

    friend std::ostream& operator<<(std::ostream& os, const Doublyll& src);

    int Length(); // public interface
};

int Doublyll::Length() {
    return LengthAux(head);
}


// Find Length how much Node in linked list
int Doublyll::LengthAux(Node* p)
{
    static int count = 0;

    if (p != NULL)
    {
        count++;
        LengthAux(p->next);
    }

    return count;
}

...

这是涉及递归的实现使用的一种非常常见的模式。递归调用的本质是函数的递归内脏的签名通常与外部调用函数的自然签名不同。