https://dart.dev/guides/language/language-tour#extending-a-class
引數型別必須與被覆寫方法的引數型別相同(或超型別)。在前面的示例中,SmartTelevision 的對比度設定器將引數型別從 int 更改為超型別 num。
我在看上面的解釋,想知道為什么子型別成員方法的引數需要比原始類的引數定義得更“廣泛”(通常)。
https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Function_types
class AnimalShelter {
Animal getAnimalForAdoption() {
// ...
}
void putAnimal(Animal animal) {
//...
}
}
class CatShelter extends AnimalShelter {
//↓ Definitions that are desirable in the commentary
void putAnimal(Object animal) {
// ...
}
//↓Definitions that are not desirable in the commentary
void putAnimal(Cat animal) {
// ...
}
//I can't understand why this definition is risky.
//What specific problems can occur?
}
我覺得這個維基百科示例代碼很容易理解,那么如果子型別的成員方法的引數被定義為更“窄”(具體)的型別,會出現什么樣的具體問題(故障)?
即使用自然語言解釋,畢竟是抽象的,所以如果你能給我一個完整的作業代碼和使用它的解釋,那將是非常有幫助的。
uj5u.com熱心網友回復:
讓我們考慮一個具有類層次結構的示例:
Animal
/ \
Mammal Reptile
/ \
Dog Cat
超類(更廣泛的型別)在子類(更窄的型別)之上。
現在假設你有類:
class Base {
void takeObject(Mammal mammal) {
// ...
}
Mammal returnObject() {
// ...
}
}
class Derived extends Base {
// ...
}
類的公共成員指定一個介面:呼叫者的契約。在這種情況下,Base該類通告一個takeObject接受任何Mammal引數的方法。因此,一個類的每個實體Base都應該符合這個介面。
遵循Liskov 替換原則,因為Derivedextends Base,Derived實體是a Base,因此它也必須符合相同Base的類介面:它的takeObject方法也必須接受任何Mammal引數。
如果被Derived覆寫takeObject以僅接受Dog引數:
class Derived extends Base {
@override
void takeObject(Dog mammal) { // ERROR
// ...
}
}
這將違反Base類介面的合同。Derived的覆寫takeObject可以使用Cat引數呼叫,根據宣告的介面應該允許Base。由于這是不安全的,Dart 的靜態型別系統通常會阻止您這樣做。(一個例外是,如果您添加covariant關鍵字以禁用型別安全并表明您個人保證Derived.takeObject永遠不會使用任何Mammal不是Dogs 的 s 來呼叫它。如果該宣告是錯誤的,您最終會遇到運行時錯誤。)
請注意,如果DerivedoverrodedtakeObject改為接受一個Animal引數也沒關系:
class Derived extends Base {
@override
void takeObject(Animal mammal) { // OK
// ...
}
}
因為這仍然符合 : 的約定:使用 anyBase.takeObject呼叫是安全的,因為所有s 也是s。Derived.takeObjectMammalMammalAnimal
請注意,回傳值的行為是相反的:被覆寫的方法可以回傳更窄的型別,但回傳更寬的型別會違反Base介面的約定。例如:
class Derived extends Base {
@override
Dog returnObject() { // OK, a `Dog` is a `Mammal`, as required by `Base`
// ...
}
}
但:
class Derived extends Base {
@override
Animal returnObject() { // ERROR: Could return a `Reptile`, which is not a `Mammal`
// ...
}
}
uj5u.com熱心網友回復:
void main(){
Animal a1 = Animal();
Cat c1 = Cat();
Dog d1 = Dog();
AnimalCage ac1 = AnimalCage();
CatCage cc1 = CatCage();
AnimalCage ac2 = CatCage();
ac2.setAnimal(d1);
//cc1.setAnimal(d1);
}
class AnimalCage{
Animal? _animal;
void setAnimal(Animal animal){
print('animals setter');
_animal = animal;
}
}
class CatCage extends AnimalCage{
Cat? _cat;
@override
void setAnimal(covariant Cat animal){
print('cats setter');
_cat = animal;
/*
if(animal is Cat){
_cat = animal;
}else{
print('$animal is not Cat!');
}
*/
}
}
class Animal {}
class Cat extends Animal{}
class Dog extends Animal{}
Unhandled Exception: type 'Dog' is not a subtype of type 'Cat' of 'animal'
在上面的代碼中,即使setAnimal方法接收到一個Dog實體,也不會出現編譯錯誤和運行時錯誤,因此需要將引數設定為與超類相同的型別,并檢查方法內部的型別。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/494859.html
上一篇:'operator='的回傳型別決議器和模棱兩可的多載
下一篇:將資料框轉換為矩陣?
