摘要:結論這個關鍵字的發揮作用是在子類去繼承父類的時候。在中,作者也說了,盡可能的在申明,傳參,返回值的時候使用父類和接口,而不要使用實現類。
動機
最近一直在使用C++寫win32程序,用了一些庫,里面提供的類和demo各種是virtual這個關鍵字,一直不是很明白到底是啥用,于是查看了一些文檔,寫小程序來實驗它的作用。
結論virtual這個關鍵字的發揮作用是在子類去繼承父類的時候。比如:
class Person { public: void foo1() { // do ... } virtual void foo2() { // do ... } };
像上面的代碼,如果類Person就一直被實例化使用,但是沒有類去繼承它的話,那么這個virtual實際上并沒有什么卵用。foo2()方法和foo1()是一樣的。
當它被繼承的時候,有兩種情況,覆寫(override)這個foo2()方法,或者不覆寫它。比如這樣:
class Student : public Person { public: void foo2() { // do something.. } }; class Teacher : public Person { public: // no override };
然后我們使用的時候,如果是子類的實例,調用foo2()方法,理所當然是執行子類中所定義的foo2()方法體。但是當將這個子類的實例強制轉型成父類的實例(指針),再去執行foo2()方法的時候,對應的兩種情況:子類實現了父類中virtual方法的,調用子類的方法;子類中沒有override的,仍然是調用父類中的實現(這不是廢話么……)
列個表格大概是這樣:
// 大前提是父類中有個`virtual`方法`foo2()` 是否override foo2() 調用子類實例的foo2() 強轉成父類后調用foo2() 子類1 是 執行子類1的foo2() 執行子類1的foo2() 子類2 否 執行父類的foo2() 執行父類的foo2() // 另一種情況 // 大前提是父類中有個方法`foo2()`,但是沒有virtual關鍵字修飾 是否override foo2() 調用子類實例的foo2() 強轉成父類后調用foo2() 子類1 是 執行子類1的foo2() 執行父類的foo2() 子類2 否 執行父類的foo2() 執行父類的foo2()與Java的對比
我的感覺好像Java自帶這個多態的特性,不需要用什么關鍵字修飾,某個實例轉換成父類后調用方法,默認就會調用子類的實現(如果有的話)。寫了個小demo實驗了一下,果然如此。
public class Main { public static void main(String[] args) { Person p = new Person(); p.foo(); // output: Person foo Student s = new Student(); s.foo(); // output: Student foo Person ps = s; ps.foo(); // output: Student foo } static class Person { public void foo() { System.out.println("Person foo"); } } static class Student extends Person { public void foo() { System.out.println("Student foo"); } } }
在《Effective Java 2e》中,作者也說了,盡可能的在申明,傳參,返回值的時候使用父類和接口,而不要使用實現類。
大概是這樣:
ArrayList總結strList = new ArrayList (); //這樣是耿直的寫法 List strList = new ArrayList (); //這樣更好,因為你可以換后面這個new // 返回值和參數也是一樣,一般能使用接口就盡量使用接口,而不要寫死成實現類,這樣帶來更大的靈活性 public List buildStrList(List raw, AnyInterface interf) { // do xxxx }
virtual關鍵字修飾的方法在子類繼承實現后,就可以達到多態的目的(使用父類的指針依然可以調用到子類的實現)。
Java中不需要這個關鍵字來達到多態,覆寫方法自帶這個功能。
參考c++ ref: polymorphism
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64969.html
摘要:繼承方式繼承方式限定了基類成員在派生類中的訪問權限,包括公有的私有的和受保護的。所以子類給父類引用賦值也是可以的,相當于給子類對象中繼承的父類部分起了別名。如圖成員函數也是如此,當子類與父類具有函數名相同的函數時,還是符合就近原則。 ...
摘要:語言通過字節碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點。有針對不同系統的特定實現,,,目的是使用相同的字節碼,它們都會給出相同的結果。項目主要基于捐贈的源代碼。 本文來自于我的慕課網手記:Java編程中那些再熟悉不過的知識點,轉載請保留鏈接 ;) 1. 面向對象和面向過程的區別 面向過程 優點: 性能比面向對象高。因為類調用時需要實例...
摘要:當子類繼承了父類并且子類重寫了父類的虛函數之后,我們可以看到此時子類中虛函數指針對應的虛函數表中存的是子類經過重寫的函數了。 前言:相信小伙伴們在學習到C++面...
摘要:也就是說,一個實例變量,在的對象初始化過程中,最多可以被初始化次。當所有必要的類都已經裝載結束,開始執行方法體,并用創建對象。對子類成員數據按照它們聲明的順序初始化,執行子類構造函數的其余部分。 類的拷貝和構造 C++是默認具有拷貝語義的,對于沒有拷貝運算符和拷貝構造函數的類,可以直接進行二進制拷貝,但是Java并不天生支持深拷貝,它的拷貝只是拷貝在堆上的地址,不同的變量引用的是堆上的...
閱讀 4095·2023-04-26 01:48
閱讀 3267·2021-10-13 09:40
閱讀 1746·2021-09-26 09:55
閱讀 3634·2021-08-12 13:23
閱讀 1792·2021-07-25 21:37
閱讀 3436·2019-08-30 15:53
閱讀 1399·2019-08-29 14:16
閱讀 1400·2019-08-29 12:59