2016-07-06 3 views
-2

У меня возникли проблемы с пониманием того, как использовать указатели, когда они находятся в «приватном».Связанные списки личные указатели C++

в основном я не знаю, как получить и установить значения для указателей

Я хочу, чтобы создать узел головы и хвоста, которые не имеют никакого значения символа. затем создайте новые узлы, которые находятся между головкой и хвостом, и добавьте новые узлы в конец списка (перед хвостом).

код запускается, но он ничего не делает, когда я использую функцию печати.

извините, если мое форматирование неверно и если код слишком длинный.

Вот код для моего класса:

#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; 
} 
+0

Я сомневаюсь, что ваша проблема не имеет ничего общего с переменными является частным. – immibis

+0

*** код запускается, но он ничего не делает, когда я использую функцию печати. ​​*** Мой совет вам научиться использовать ваш отладчик. Один шаг через код, смотрящий на переменные .. – drescherjm

+0

Вы либо неправильно поняли концепцию связанных списков, либо указатели C++. Если у вас нет элементов, тогда вы должны создать новый узел, который станет как головой, так и хвостом, а затем установите для него правые и левые соседи в значение «nullptr».Просмотрите инструкцию 'if' внутри' append', она включает ** неопределенное поведение **. – K117

ответ

0

privateprivate Члены, указатели или другие данные - это данные, которые объект либо не хочет испортить кому-либо еще, либо хочет знать, с кем-то с ними столкнулся.

Способы сета и геттера позволяют получить доступ к члену private, но контролируемым образом. Например, если у вас есть личное целое число, которое ни при каких обстоятельствах не может быть больше десяти, вы можете иметь код в сеттере, который проверяет, что вызывающий объект пытается вывести значение из диапазона и отклонить запрос.

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

Теперь программа не может иметь каких-либо неприятных сюрпризов с X == 11, создающего вне диапазона доступа или любой другой.

Это самооборона для объектов. Они сохраняют контроль над тем, кто устанавливает свои данные для чего и может поддерживать согласованность. Скажем, у вас более сложный случай, когда вы не можете пробовать A/D более 10000 выборок в секунду с включенным фильтром FIR без голодания процессора и блокировки системы. Упс. Если единственный способ установить состояние фильтра или частоту дискретизации - через сеттеры в объекте диспетчера A/D, объект может протестировать и отклонить и предотвратить катастрофу (и, возможно, оставить сообщение с хорошим сообщением в маске, указывающее на плохого актера).

Подумайте очень сложно, прежде чем внедрять геттер, который возвращает ссылку на константу или указатель. Как только вызывающий абонент имеет либо, они могут делать все, что захотят, с возвращенными данными.

Правило большого пальца по умолчанию равно паранойи: не допускайте доступа к каким-либо данным без уважительной причины, а затем предпочитайте контролируемый доступ через сеттеры и геттеры.

О специфике вашей проблемы.

Геттеры и сеттеры для узла связи часто являются ставкой присоски. Узел, скорее всего, не может определить для себя, если ссылка действительна. Только менеджер списка может. Это тот случай, когда сам объект слишком незначителен, чтобы знать, что безопасно, поэтому вам нужно открыть внутренности для другого объекта, который знает больше. friend полезен здесь, хотя часто бывает лучше сделать ссылки узла public и никогда не разрешать диспетчеру списка давать узел клиенту.

Коэффициенты хорошие, клиент не должен знать абсолютно ничего о том, как список работает в любом случае. Прочтите на сцепление.

Итак, узел должен быть совершенно глупым. Это означает, что вам нужно иметь класс ListManager, чтобы (duh) управлять списком и защищать node от плохо действующих актеров.

ListManager содержит ваш head, tail, root или что-то вместе с append и remove, print и другими методами управления списком. Ни при каких обстоятельствах никакая из этих функций не вызывает 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 также нуждается в деструкторе для обработки delete всех добавленных узлов new. Ему также нужен конструктор копирования и оператор присваивания, чтобы сделать его правилом три. «What is The Rule of Three?» спросите вы? Это очень важно. Прочтите ссылку, чтобы сохранить большую часть будущей отладки. Несоблюдение правила из трех приводит к непропорциональному числу вопросов на 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; 
} 
+0

Большое вам спасибо! Это было очень полезно. –

0

Во-первых, голова и хвост должен инициализируется в NULL, поскольку в начале ничего нет.

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

Затем измените свой код, чтобы добавить, в частности, оператор first if. изменить код

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

Поскольку вы начинаете новый список, как голова и хвост такой же узел, который вы только что вставили.

Наконец, измените условие цикла while в функции печати. Что-то простое, как это должно сработать.

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

Вы хотите распечатать текущий узел, даже если у него нет правого соседа.

+0

Спасибо, что работает намного лучше. –

Смежные вопросы