背景
我是 Dart 新手,最近我一直在閱讀一些關于 Dart 聲音型別系統的檔案,直到我遇到了一個名為
我對什么感到困惑
我的問題是,當然,通過在覆寫方法中禁止引數型別“收緊”,我們可以防止
定義一只貓并在鱷魚之后發送它
class Animal {
chase(Animal a) {}
}
class Mouse extends Animal {}
class Alligator extends Animal {}
class CatA extends Animal {
@override
// error on this line
void chase(Mouse x) {} // It makes sense. Cat chases Mouse
}
class CatB extends Animal {
@override
// error on this line
void chase(Alligator x) {} // Cat chases Alligator ? You can't be serious!
}
但是使用一個Object(witch 是幾乎所有其他人的超型別)作為它的引數型別怎么樣?
class Cat extends Animal {
@override
void chase(Object x) { // Now this Cat can chase anything.....
}
}
void main() {
var cat = Cat();
cat.chase(Alligator()); // Again, we are trying to let a little pussy chase a terrifying beast!
}
// This piece of code works
這到底是怎么回事,這對我來說根本沒有意義......此外,如果我創建一個擴展 a 的超級貓怎么辦Cat,它確實可以追逐 aAlligator
class SuperCat extends Cat {
@override
// error on this line
void chase(Alligator x) { // I make a SuperCat chasing after a Alligator intentionally, but it doesn't work...
}
}
上面的這些事情真的讓我大吃一驚,我是不是在某種程度上弄錯了,還是在引擎蓋下還有什么東西可以做到這一點?
更新
感謝@jamesdlin 和@Abion47,我終于可以弄清楚大部分謎題,但還有一個問題需要解決。正如@jamesdlin 提到的,contract of the base class method在覆寫方法時必須遵守。以AnimalandCat為例,Animal.chase做一個契約說chasemust compatible to accept any Animal, 不管是Alligatoror
Mouse,但是這個契約是否也做了一個限制,chase不能接受任何其他的Objectexception forAnimal?(自然會想到因為你不能將臨時Object引數傳遞給Animal.chase)如果是這樣,為什么 Dart 允許將Cat.chase引數型別從Animalto擴大Object?它不違反由Animal.chase?
uj5u.com熱心網友回復:
jamesdlin 參考的答案詳細說明了為什么不允許這樣做,但我會嘗試給出一個簡明扼要的版本。
abstract class Animal {
void chase(Animal a) { ... }
}
class Mouse extends Animal {}
class Alligator extends Animal {}
class Cat extends Animal {
@override
void chase(Mouse x) { ... } // No-no
}
從理論上講,這很好,因為MouseextendsAnimal并且Cat只是限制了可以傳遞給的動物種類chase。
但是想想多型性會發生什么。硬性規則是任何擴展和覆寫基類的類都必須與該基類兼容。這確保了,即使在鍵入基類的句柄上呼叫函式,也可以保證呼叫將轉到覆寫類中的正確函式定義。
這就是使抽象類成為可能的原因——如果派生類中的函式實作與基類中的相同函式不兼容,則不可能將繼承類的實體視為基類。
例如,以文章中的示例為例,但不是顯式創建 a Cat,而是讓它成為一些隨機生成的動物:
Animal a = RandomAnimalFactory.create();
a.chase(Alligator());
的確切型別是a什么?你沒有辦法知道。你所知道的是它是Animal.
現在看看對a.chase(Alligator()). 那會成功嗎?嗯,是的,因為Animal.chase需要一個Animal并且Alligator是一個Animal。那里沒有問題。
但是想象一下子類是否可以限制該引數的型別,例如是否Cat可以將其限制為Mouse. 現在還不清楚那個呼叫是否會成功,因為即使你知道那a是一個Animal,你也不知道是什么樣的Animal。如果它是一個Alligator不再是有效引數的型別怎么辦?為了知道,型別系統必須解包變數的宣告型別以檢查實際型別,然后才知道呼叫是否成功。這與繼承背道而馳,繼承基型別的型別可以與它的任何兄弟型別互換。
一下子,原本簡單的事情變得例外復雜。它不僅使基于 OOP 的型別系統的實作更加復雜,而且完全破壞了繼承的意義。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/494755.html
