簡體   English   中英

從衍生**轉換為基礎**

[英]Conversion from Derived** to Base**

我正在閱讀此書 ,不幸的是無法深入了解為什么編譯器不允許從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**進行了轉換,則可以在類型系統承諾僅存在指向香蕉的指針的情況下放置一個指向Apple的指針。 繁榮!

這將不乏無意義的錯誤:

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 <stdio.h>

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的指針。

核潛艇潛艇; 核潛艇* subPtr =⊂

這也是合法的,但如果可以的話

Vehicle** vehiclePtrPtr = carPtrPtr;

你可能會意外地做

*vehiclePtrPtr = subPtr;

*vehiclePtrPtr是指向Car的指針。 在最后一行中,您為它分配了一個Sub的指針。 因此,您現在可以在Car類型的對象上以未定義的行為調用在派生類Sub定義的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM