Загадочное сообщение об ошибке при передаче константных параметров в качестве аргументов

Итак, я пишу реализацию двусвязных списков. Это конструктор класса, реализующий отдельные узлы:

DNode::DNode(const int a_key, const DNode* a_prev, const DNode* a_next) 
    : key(a_key), prev(a_prev), next(a_next) {}

Причина, по которой я написал const int a_key, const DNode* a_prev, const DNode* a_next, заключается в том, что у конструктора нет причин их изменять. Поэтому я просто хочу защитить себя от нежелательных изменений внутри конструктора. Хорошо ли это делать?

Компиляция выдает следующую ошибку:

dnode.cpp:6:89: ошибка: невозможно инициализировать подобъект-член типа «DNode *» с lvalue типа «const DNode *» DNode::DNode(const int a_key, const DNode* a_prev, const DNode* a_next) : ключ(a_key), предыдущий(a_prev), следующий(a_next) {}

dnode.cpp:6:103: ошибка: невозможно инициализировать подобъект-член типа «DNode *» с lvalue типа «const DNode *» DNode::DNode(const int a_key, const DNode* a_prev, const DNode* a_next) : ключ(a_key), предыдущий(a_prev), следующий(a_next) {}

Я не понимаю сообщение об ошибке. DNode* - это тип указателя, а не lvalue. Любая помощь приветствуется.

=== ИЗМЕНИТЬ ===

Я изменил свой код следующим образом.

dnode.h

class DNode {

 public:

  //
  DNode( const int a_key, const DNode& a_prev, const DNode& a_next );

  //
  int get_key() const;
  DNode* get_prev() const;
  DNode* get_next() const;

  //
  void set_key( const int a_key );
  void set_prev( const DNode& a_prev );
  void set_next( const DNode& a_next );

  //
 private:

  int key;
  DNode* prev;
  DNode* next;

};

dnode.cpp

//
DNode::DNode( const int a_key, const DNode& a_prev, const DNode& a_next ) 
: key(a_key), prev(&a_prev), next(&a_next) {}

//
int DNode::get_key() const { return key; }
DNode* DNode::get_prev() const { return prev; }
DNode* DNode::get_next() const { return next; }

//
void DNode::set_key( const int a_key ) { key = a_key; }
void DNode::set_prev( const DNode& a_prev ) { prev = &a_prev; }
void DNode::set_next( const DNode& a_next ) { next = &a_next; }

Я получаю следующее сообщение об ошибке

dnode.cpp:6:89: ошибка: невозможно инициализировать подобъект-член типа «DNode *» с rvalue типа «const DNode *» DNode::DNode(const int a_key, const DNode& a_prev, const DNode& a_next): ключ (a_key), предыдущая(&a_prev), следующая(&a_next) {}

dnode.cpp:6:104: ошибка: невозможно инициализировать подобъект-член типа «DNode *» с rvalue типа «const DNode *» DNode::DNode(const int a_key, const DNode& a_prev, const DNode& a_next): ключ (a_key), предыдущая(&a_prev), следующая(&a_next) {}

dnode.cpp: 15:52: ошибка: присвоение «DNode *» из несовместимого типа «const DNode *» void DNode:: set_prev (const DNode & a_prev) { prev = &a_prev; }

dnode.cpp: 16:52: ошибка: присвоение «DNode *» из несовместимого типа «const DNode *» void DNode:: set_next (const DNode & a_next) { next = &a_next; }

Еще раз, причина, по которой я пишу const DNode& a_prev в списке параметров конструктора, заключается в том, что я хочу предотвратить изменение a_prev конструктором (но меня не волнует, изменяется ли он снаружи). Но поскольку это не работает, я мог неправильно понять использование const в этом контексте.


person usual me    schedule 17.10.2013    source источник
comment
Как передать аргументы конструктору?   -  person Suvarna Pattayil    schedule 17.10.2013
comment
Я только что отредактировал ваш код конструктора, разбив его на две разные строки, чтобы сделать его более читабельным.   -  person Mr.C64    schedule 17.10.2013


Ответы (3)


Я думаю, что внутри вашего класса у вас есть члены данных (которые вы не показали), определенные как:

DNode* prev;
DNode* next;

В конструкторе у вас есть const DNode* параметров (a_prev и a_next):

DNode::DNode(const int a_key, const DNode* a_prev, const DNode* a_next) 
   : key(a_key), prev(a_prev), next(a_next) {}

const DNode* означают, что у вас есть указатель на DNode, который является константным, т. е. тот, на который указывает DNode, не может быть изменен.
Но вы хотите присвоить его DNode* членам данных, которые не являются -const (то есть то, на что указывает DNode, можно изменить).
Вы не можете назначить что-то, что ограничено как const (т.е. не может быть изменено), чему-то, что не является const (т.е. его можно изменить).

Следующий код должен работать:

// Remove 'const' from the pointers!
DNode::DNode(const int a_key, DNode* a_prev, DNode* a_next) 
  : key(a_key), prev(a_prev), next(a_next) {}

Если вы хотите использовать этот стиль «const для входных параметров», например const int a_key, вы должны поместить const между символом указателя (*) и именем параметра, например.

// Proper placing of 'const'
DNode::DNode(const int a_key, DNode* const a_prev, DNode* const a_next) 
  : key(a_key), prev(a_prev), next(a_next) {}

Это означает, что a_prev и a_next нельзя переназначить так, чтобы они указывали на другие данные; но они указывают на то, что можно изменить (DNode*).

person Mr.C64    schedule 17.10.2013
comment
Спасибо. Он скомпилировался при удалении const из параметров. Я думаю, что неправильно понял значение const в этом контексте. Я думал, что это означает, что параметр не должен изменяться при вызове функции. Но на самом деле это означает, что параметр является const объектом и не должен изменяться никогда, независимо от вызовов функций. Это правильно? - person usual me; 17.10.2013
comment
@ jfk916: это зависит от того, где вы поместите const. Если у вас есть const X* p, это означает, что экземпляр X указывает на const, но p можно изменить, например, на указывая на что-то другое. Если у вас есть X * const p, это означает, что p не может быть изменено (и не может указывать на что-то другое), но X может быть изменено (не является константой). Если у вас const X * const p, то p и X являются const и не могут быть изменены. - person Mr.C64; 17.10.2013
comment
@ jfk916: Если вы найдете ответ полезным, рассмотрите возможность голосования +1. - person Mr.C64; 17.10.2013

Вы пытаетесь инициализировать указатель на неконстантный объект указателем на константный объект. Может быть, вы хотели передать константные указатели на неконстантные объекты? Тогда это будет DNode* const a_prev.

person Ivan Ishchenko    schedule 17.10.2013

Похоже, что члены DNode a_prev и a_next являются указателями на неконстантные объекты. Несколько вариантов:

  • Превратите эти элементы в указатели на константные объекты.
  • Поместите элементы в стек и передайте разыменованные аргументы в списке инициализатора, чтобы вызвать конструктор копирования.*
  • Куча выделяет элементы в конструкторе и передает разыменованные аргументы в вызовы конструктора копирования.*
  • Возьмите неконстантные аргументы для этих указателей.

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

person Grimm The Opiner    schedule 17.10.2013