Как я могу построить объекты в конструкторе и назначить ссылку? - PullRequest
0 голосов
/ 07 ноября 2019

У меня есть класс Tree с тремя переменными экземпляра, называемыми board (Board), root (Node) и end (Point). Дополнительно он имеет конструктор из шести параметров. Я хочу создать объекты внутри конструктора и назначить их ссылкам (переменным экземпляра).

Когда я пытаюсь назначить корень, я получаю function "Node::operator=(const Node &)" (declared implicitly) cannot be referenced -- it is a deleted function ошибку.

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

/* HEADER FILE */
class Tree {
public:
    Tree(int boardHeight, int boardWidth, int knightStartXPosition,
    int knightStartYPosition, int knightEndXPosition, int knightEndYPosition);

private:
    Board& board; // Board has int height and int width.
    Node& root; // Node has location (Point) and end (Point)
    Point& end; // A point is a plane vector of x and y.

    void jumpNodes(Node* node); // not used yet
};
/* IMPLEMENTATION FILE */
Tree::Tree(int boardHeight, int boardWidth, int knightStartXPosition,
    int knightStartYPosition, int knightEndXPosition, int knightEndYPosition) {
        Point start = Point(knightEndXPosition, knightEndYPosition);
        Point end = Point(knightStartXPosition, knightStartYPosition);
        Node root = Node(start, end);

        this->board = Board(boardHeight, boardWidth);
        this->root = root; // this line gives the error
        this->end = end;
};

Ожидаемое решение - конструктор работает с заданными параметрами, но если это невозможно, мне нужны входные данные и структура.

Ответы [ 2 ]

0 голосов
/ 08 ноября 2019

Прежде всего, вы не должны использовать референтные члены для этой цели. Они предназначены для случаев, когда имя должно ссылаться на объект, который уже существует.

Класс может выглядеть следующим образом:

class Tree {
public:
    Tree(int boardHeight, int boardWidth, Point knightStart, Point knightEnd);

private:
    Board board;
    Node root;
    Point end;
};

/* IMPLEMENTATION FILE */
    Tree::Tree(int boardHeight, int boardWidth, Point knightStart, Point knightEnd)
        : Board(boardHeight, boardWidth), root(knightStart, knightEnd), end(knightEnd) {}

, который вы видите намного проще, чем тот, который у вас есть в настоящее время. Фактически, было бы обычной практикой иметь встроенное тело заголовка в заголовке, так как он только инициализирует элементы и не делает ничего сложного.

Когда я пытаюсь назначить корень, я получаю функцию "Узел":: operator = (const Node &) "(объявлен неявно) не может быть указан - это ошибка удаленной функции.

Это сообщение, вероятно, указывает на то, что вы сделали аналогичную вещь в Node class, т.е. использует ссылочные переменные в качестве членов, что отключает неявное присваивание ( см. здесь для причины). Вам также следует изменить дизайн других классов, чтобы в этом случае ссылки не использовались.

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

Если бы этот код был Java, он бы работал.

C ++ отличается от Java, и вам лучше привыкнуть к этому факту. Если вы используете элемент типа std::shared_ptr<Board> вместо Board, тогда он будет иметь семантику , аналогичную (но не идентичную) ссылкам на Java. Однако это будет считаться плохим стилем в C ++, если вы специально не собираетесь использовать один объект платы для нескольких деревьев.

В C ++ ссылочная переменная не выполняет управление временем жизни объекта, к которому вы привязаны;и, кроме того, оно должно быть связано с инициализацией, и переподключение невозможно. Надеюсь, ясно, что это не подходит для того, как вы его используете. Он имеет другое назначение и поведение по сравнению с Java-ссылкой, несмотря на то же имя.

0 голосов
/ 07 ноября 2019

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

Во-вторых, ссылка являетсякак неизменный указатель (указатель, который не может изменить то, на что он указывает), и ваши ссылочные элементы уже инициализированы при вводе функции Body, поэтому они не могут быть перенаправлены.

Для правильной инициализации ссылки на элемент используйтесписок инициализации:

Foo::Foo(int& bar, float& baz) : m_bar(bar), m_baz(bar) {...}

Где Foo - имя класса, bar и baz аргументы, m_bar и m_baz - члены. Обратите внимание на : и &

Также я думаю, что в вашем случае вы действительно хотите сохранить их по значению, по крайней мере я не вижу причин для ссылки, так как все аргументы передаются по значению. Ссылка должна ссылаться на что-то, что где-то должно храниться

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