【问题标题】:Linked List private pointers C++ [closed]链表私有指针 C++ [关闭]
【发布时间】:2016-11-09 03:09:09
【问题描述】:

当指针处于“私有”状态时,我无法理解如何使用指针。

主要是我不知道如何获取和设置指针的值

我想创建一个没有字符值的头尾节点。 然后创建位于头部和尾部之间的新节点,并将新节点添加到列表的末尾(尾部之前)。

代码运行,但是当我使用打印功能时它什么也没做。

对不起,如果我的格式错误并且代码太长。

这是我班级的代码:

#include <iostream>
using namespace std;

class node
{
public:
  node(void)// constructor for empty nodes
  {
    left_link = NULL;
    right_link = NULL;
  }
  node(char x) // constructor for nodes with given value
  : anything(x)
  { }
  char get_char() // return character
  {
    return anything;
  }
  void setLeftLink(node *left)
  {
    left_link = left;
  }
  void setRightLink(node *right)
  {
    right_link = right;
  }
  node *getlefttLink()
  {
    return left_link;
  }
  node *getRightLink()
  {
    return right_link;
  }

private:
  node *left_link;
  char anything;
  node *right_link;
};

这是我的功能:

void append(node *&head, node *&tail);
void print(node *head);


void append(node *&head, node *&tail)
{
  char c;
  cout << "Please enter a single character: ";
  cin >> c;
  node *current = new node(c);
  cout << current->get_char() << endl;
  if(head == NULL && tail == NULL)
  {
    head->setRightLink(current);
    tail->setLeftLink(current);
    current->setLeftLink(head);
    current->setRightLink(tail);
  }
  else
  {
    tail->setRightLink(current);
    current->setLeftLink(tail);
    tail = current;
    tail->setRightLink(NULL);
  }

}
// print function
void print(node *head)
{
  node* temp;
  temp = head;
  while(temp->getRightLink()!=NULL){
    cout<<temp->get_char()<<endl;
    temp = temp->getRightLink();    
  }
}

这是我的主要内容:

int main()
{
char choice;
node *head = new node;
node *tail = new node;

cout << "Please choose one menu option at a time:\n" 
    << "1 = Append\n"
    << "2 = Print list\n"
    << "3 = Exit\n\n";


    do
    {
        cout << "Menu option(1-3): ";
        cin >> choice;

        switch (choice)
        {
            case '1': append(head, tail); // add to the end of list.
                break;
            case '2': print(head); // print list
                break;
            case '3': cout << "end program\n\n";
                break;
            default: cout << "try again\n";
                break;
        }


    }while(choice != '3');

return 0;
}

【问题讨论】:

  • 我怀疑您的问题与私有变量有关。
  • 代码运行,但是当我使用打印功能时它什么也没做。我给你的建议是学会使用你的调试器。单步执行查看变量的代码..
  • 您要么误解了链表概念,要么误解了 C++ 指针。如果你没有元素,那么你必须创建一个新的节点,它将成为头和尾,然后将它的左右邻居设置为nullptr。查看append 函数中的if 语句,它涉及未定义的行为

标签: c++ class pointers linked-list private


【解决方案1】:

private 成员、指针或其他数据是对象不想被其他人弄乱或想知道是否有人弄乱它们的数据。

Setter 和 getter 方法允许访问 private 成员,但以受控方式。例如,如果您有一个在任何情况下都不能大于 10 的私有整数,您可以在 setter 中编写代码来检查调用者是否试图强制该值超出范围并拒绝请求。

bool setX( int newX)
{
    if (newX > 10)
    {
        return false;
    }
    else
    {
        X = newX;
        return true;
    }
}

现在程序不会有任何令人讨厌的意外,因为 X == 11 会导致超出范围的访问等。

这是对物体的自卫。他们可以控制谁将他们的数据设置为什么,并且可以保持一致性。假设您有一个更复杂的情况,您无法在启用 FIR 滤波器的情况下以每秒超过 10000 个样本的速度对 A/D 进行采样,而不会导致 CPU 处于饥饿状态并锁定系统。哎呀。如果设置过滤器状态或采样率的唯一方法是通过 A/D 管理器对象中的设置器,则该对象可以测试和拒绝并防止灾难(并可能留下一条指向坏演员的漂亮的胖日志消息)。

在实现返回非常量引用或指针的 getter 之前,请三思而后行。一旦调用者拥有其中任何一个,他们就可以对返回的数据做任何他们想做的事情。

经验法则是默认偏执狂:在没有充分理由的情况下不授予对任何数据的访问权限,然后更喜欢通过 setter 和 getter 进行受控访问。

具体问题。

链接节点的获取器和设置器通常是一个傻瓜赌注。节点很可能无法自行确定链接是否有效。只有列表管理器可以。在这种情况下,对象本身太无知,不知道什么是安全的,因此您必须向另一个了解更多的对象开放内部结构。 friend 在这里很有用,但通常最好将节点的链接设为public,并且永远不要让列表管理器将节点提供给客户端。

很有可能客户应该对列表的工作原理一无所知。阅读耦合。

所以节点应该是完全愚蠢的。这意味着您需要有一个 ListManager 类来(duh)管理列表并保护 nodes 免受行为不端的演员的侵害。

ListManager 包含您的headtailroot 或其他任何内容以及appendremoveprint 和其他列表管理方法。在任何情况下,这些函数中的任何一个都不会向调用者透露node,尽管它们可以返回可用于引用节点的句柄或迭代器,而不会给调用者提供破坏列表的工具。迭代器是一个值得他们自己提出问题的话题,并且可能已经有很多了。

解释上面的代码是有序的。请注意,我已标记但未更正我发现的逻辑问题。编译时可能会有更多内容(启用 C++11),但我没有运行它。

class ListManager
{
private:
    class node
    {
    public:
        node *left_link = nullptr; // recommendation: immediately set or NULL all 
                                   // pointers unless you have a well documented 
                                   // reason not to and profiling to back it up.
                                   // The time you save can be enormous.
        char anything;
        node *right_link = nullptr;
    };
    node *head = nullptr;
    node *tail = nullptr;

public:

    void append(char c) // head and tail not required ListManager members
    {
        /* removed because the append function should append and only append.
         * If you want to read data from the user, call a read function first 
         * and pass it read character in to append
         * Do one thing and do it well. Every time you add behaviours to a 
         * function, you make it harder to debug. For example, what happens to 
         * the linked list if you fail to read a character? That shouldn't be 
         * append's problem. 
        char c;
        std::cout << "Please enter a single character: ";
        std::cin >> c;
        */
        node *current = new node();

        current->anything = c;
        //std::cout << current->anything << std::endl; removed for same reason as above.

        // think on this: how can head and tail NOT both be NULL at the same time?
        // if you find a way, you have a bug that needs fixing.
        if (head == nullptr && tail == nullptr) 
        {
            // If head is NULL, it has no right_link to assign. This will fail horribly.
            head->right_link = current;
            tail->left_link = current;
            current->left_link = head;
            current->right_link = tail;
            /* Consider instead
            head = current;
            tail = current;
            */ 
        }
        else
        {
            tail->right_link = current;
            current->left_link = tail;
            tail = current;
            tail->right_link = nullptr; // don't need to do this. node constructor 
                                        // ensures current->right_link is NULL
        }
    }
    // print function
    void print() // no parameters required. head is ListManager member
    {
        node* temp;
        temp = head;
        // Again, if head is NULL, temp will be NULL and there will be no right_link
        // consider instead
        // while (temp != nullptr)
        while (temp->right_link != nullptr)
        {
            std::cout << temp->anything << std::endl;
            temp = temp->right_link;
        }
    }
};

注意node 是如何直接构建到ListManager 中的,并且是private。现在只有ListManager 可以访问node,并且拥有完全的访问权限。

ListManager 还需要一个析构函数来处理 deleteing 所有附加的 newed 节点。它还需要一个复制构造函数和一个赋值运算符以使其符合三规则。 “What is The Rule of Three?”你问?这是非常非常重要的。阅读链接可以为自己节省更多的调试时间。不遵守三法则会导致 Stack Overflow 上的 C++ 问题数量不成比例,进一步夸大这一统计数据是没有意义的。

用法:

int main()
{
    ListManager list;
    char choice;
    std::cout << "Please choose one menu option at a time:\n" << "1 = Append\n"
            << "2 = Print list\n" << "3 = Exit\n\n";

    do
    {
        std::cout << "Menu option(1-3): ";
        std::cin >> choice;

        switch (choice)
        {
            case '1':
                list.append('a'); // add to the end of list.
                break;
            case '2':
                list.print (); // print list
                break;
            case '3':
                std::cout << "end program\n\n";
                break;
            default:
                std::cout << "try again\n";
                break;
        }

    } while (choice != '3');

    return 0;
}

【讨论】:

  • 非常感谢!这很有帮助。
【解决方案2】:

首先,head 和 tail 应该初始化为 NULL,因为开头没有任何内容。

node *head = NULL;
node *tail = NULL;

然后将代码更改为追加,尤其是第一个 if 语句。 将您的代码更改为

if(head == NULL && tail == NULL)
{
    head = current;
    tail = current;
}

由于您正在开始一个新列表,因此 head 和 tail 都是您刚刚插入的同一个节点。

最后在 print 函数中更改 while 循环的条件。像这样简单的东西应该可以工作。

while (temp) {
    cout << temp->get_char() << endl;
    temp = temp->getRightLink();
}

你想打印当前节点,即使它没有正确的邻居。

【讨论】:

  • 谢谢,效果好多了。
猜你喜欢
  • 2012-02-10
  • 2020-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-29
相关资源
最近更新 更多