class Animal { name: string; constructor(theName: string) { this.name = theName; } move(distanceInMeters: number = 0) { console.log(`${this.name} moved ${distanceInMeters}m.`); } } class Snake extends Animal { constructor(name: string) { super(name); } move(distanceInMeters = 5) { console.log("Slithering..."); super.move(distanceInMeters); } } class Horse extends Animal { constructor(name: string) { super(name); } move(distanceInMeters = 45) { console.log("Galloping..."); super.move(distanceInMeters); } print() { console.log("Horse:say hello"); } } let sam = new Snake("Sammy the Python"); let tom: Animal = new Horse("Tommy the Palomino"); sam.move(); tom.move(34); tom.print();///vscode 編譯器在語法上會報錯,但是執行程序,仍然會輸出 "Horse:say hello" 不太明白為啥。
tom是Animal類型,該類型里面沒有 print 方法,應該當錯誤處理。雖然在js下面可以正確輸出,但是還是不建議這么用。
我們可以對比C++虛函數和多態的用法來理解這里。。。在TypeScript里面,類里面的方法,默認都是 public, virtual 的。
請參考這篇文章來理解虛函數和多態。https://www.cnblogs.com/music-liang/p/12726786.html
請特別注意,聲明的類型,和new的時候的類型。。。
聲明的時候是什么類型,它就是什么類型的。所以,tom.print() 會被編譯器報錯。
關於tom.move(),而TypeScript里面默認的函數都是虛函數。因為由於virtual的存在,所以,聲明的類型是父類類型(Animal),new的是子類類型(Horse),子類的虛函數覆蓋了父類的虛函數(多態特性)。。
所以,tom.move() 會調用 Horse類的move方法。。
1.必須有構造函數 constructor
2.必須在構造函數里面,給屬性賦值。這里有用到 this 關鍵字
3.繼承函數,必須在構造函數里面調用 super()函數,讓父類的構造函數先執行。。。蛋疼啊。。
這里派生類包含了一個構造函數,它 必須調用 super(),它會執行基類的構造函數。 而且,在構造函數里訪問 this的屬性之前,我們 一定要調用 super()。 這個是TypeScript強制執行的一條重要規則。
這個例子演示了如何在子類里可以重寫父類的方法。
Snake類和 Horse類都創建了 move方法,它們重寫了從 Animal繼承來的 move方法,使得 move方法根據不同的類而具有不同的功能。 注意,即使 tom被聲明為 Animal類型,但因為它的值是 Horse,調用 tom.move(34)時,它會調用 Horse里重寫的方法
abstract class Department { constructor(public name: string) { } printName(): void { console.log('Department name: ' + this.name); } abstract printMeeting(): void; // 必須在派生類中實現 } class AccountingDepartment extends Department { constructor() { super('Accounting and Auditing'); // 在派生類的構造函數中必須調用 super() } printMeeting(): void { console.log('The Accounting Department meets each Monday at 10am.'); } generateReports(): void { console.log('Generating accounting reports...'); } } let department: Department; // 允許創建一個對抽象類型的引用 //department = new Department(); // 錯誤: 不能創建一個抽象類的實例 department = new AccountingDepartment(); // 允許對一個抽象子類進行實例化和賦值 department.printName(); department.printMeeting(); department.generateReports(); // 錯誤,這個是Department類型的。。。 let department2 = new AccountingDepartment(); // 允許對一個抽象子類進行實例化和賦值 department2.printName(); department2.printMeeting(); department2.generateReports(); // 正確...
抽象基類的繼承,和普通類的繼承有點不一樣。。