Преобразование из производного ** в базу **

Я читал это и, к сожалению, не мог понять, почему компилятор не разрешает преобразование из Derived ** в Base **. Также я видел это, что дает больше информации, чем ссылка parashift.com.

РЕДАКТИРОВАТЬ:

Проанализируем этот код по строкам:

Car car; Car* carPtr = &car; Car** carPtrPtr = &carPtr; //MyComment: Until now there is no problem! Vehicle** vehiclePtrPtr = carPtrPtr; // This is an error in C++ //MyComment: Here compiler gives me an error! And I try to understand why. //MyComment: Let us consider that it was allowed. So what?? Let's go ahead! NuclearSubmarine sub; NuclearSubmarine* subPtr = ⊂ //MyComment: this two line are OK too! *vehiclePtrPtr = subPtr; //MyComment: the important part comes here... *vehiclePtrPtr is a pointer to //MyComment: a vehicle, particularly in our case it points to a Car object. //MyComment: Now when I assign to the pointer to the Car object *vehiclePtrPtr, //MyComment: a pointer to NuclearSubmarine, then it should just point to the //MyComment: NuclearSubmarine object as it is indeed a pointer to a Vehicle, //MyComment: isn't it? Where is my fault? Where I am wrong? // This last line would have caused carPtr to point to sub! carPtr->openGasCap(); // This might call fireNuclearMissle()! 

Это в основном по той же причине, почему миска с бананами – это не чаша фруктов. Если чаша из бананов была чашей с фруктами, вы могли бы положить яблоко в миску, и она больше не была бы баной для бананов.

Пока вы только проверяете чашу, конверсия безвредна. Но как только вы начнете его изменять , преобразование становится небезопасным. Это ключевой момент, чтобы иметь в виду. (Это точная причина, по которой неизменяемые коллекции Scala фактически позволяют конвертировать, но изменчивые коллекции запрещают это).

То же самое с вашим примером. Если бы было преобразование из Derived** в Base** , вы могли бы поместить указатель на яблоко, если бы система типов обещала, что существует только указатель на бананы. Boom!

Нет недостатка в бессмысленных ошибках, которые позволили бы:

 class Flutist : public Musician ... class Pianist : public Musician ... void VeryBad(Flutist **f, Pianist **p) { Musician **m1=f; Musician **m2=p; *m1=*m2; // Oh no! **f is supposed to be a Flutist and it's a Pianist! } 

Вот полный рабочий пример:

 #include  class Musician { public: Musician(void) { ; } virtual void Play(void)=0; }; class Pianist : public Musician { public: Pianist(void) { ; } virtual void Play(void) { printf("The piano blares\n"); } }; class Flutist : public Musician { public: Flutist(void) { ; } virtual void Play(void) { printf("The flute sounds.\n"); } }; void VeryBad(Flutist **f, Pianist **p) { Musician **m1=f; Musician **m2=p; *m1=*m2; // Oh no! **f is supposed to be a Flutist and it's a Pianist! } int main(void) { Flutist *f=new Flutist(); Pianist *p=new Pianist(); VeryBad(&f, &p); printf("Mom is asleep, but flute playing wont bother her.\n"); f->Play(); // Since f is a Flutist* this can't possibly play piano, can it? } 

И здесь это в действии:

 $ g++ -fpermissive verybad.cpp -o verybad verybad.cpp: In function void VeryBad(Flutist**, Pianist**): verybad.cpp:26:20: warning: invalid conversion from Flutist** to Musician** [-fpermissive] verybad.cpp:27:20: warning: invalid conversion from Pianist** to Musician** [-fpermissive] $ ./verybad Mom is asleep, but flute playing wont bother her. The piano blares 

Vehicle** vehiclePtrPtr = carPtrPtr; не допускается, потому что это преобразование Derived** в Base** , которое недопустимо.

Причина, почему это недопустимо, проиллюстрирована в вашем примере.

  Car car; Car* carPtr = &car; Car** carPtrPtr = &carPtr; 

так что carPtrPtr указывает на указатель на Car .

Подразделение NuclearSubmarine; NuclearSubmarine * subPtr = ⊂

это также законно, но если бы вы могли это сделать

 Vehicle** vehiclePtrPtr = carPtrPtr; 

вы можете случайно

 *vehiclePtrPtr = subPtr; 

это *vehiclePtrPtr – указатель на Car . с этой последней строкой вы назначаете ему указатель на Sub . Таким образом, теперь вы можете вызывать метод, определенный в производном classе Sub для объекта типа Car с неопределенным поведением.

  • Что означает «разыменование» указателя?
  • Выражения указателя: * ptr ++, * ++ ptr и ++ * ptr
  • Свободно (ptr), где ptr является NULL поврежденной памятью?
  • указатель указателя в связанном списке добавить
  • C ++: указатель на элемент данных classа ":: *"
  • C ++ Возвращаемый массив многомерности из функции
  • Почему не является законным преобразовывать «указатель на указатель на не-const» в «указатель на указатель на const»,
  • Возвращаемые массивы из функции в c ++
  • как получить hexdump структурных данных
  • Может ли указатель (адрес) быть отрицательным?
  • Вызов метода с приемником указателя объектом вместо указателя на него?
  • Давайте будем гением компьютера.