最近一直在使用C++寫win32程序,用了一些庫,裏面提供的類和demo各類是virtual
這個關鍵字,一直不是很明白究竟是啥用,因而查看了一些文檔,寫小程序來實驗它的做用。java
virtual
這個關鍵字的發揮做用是在子類去繼承父類的時候。好比:c++
class Person { public: void foo1() { // do ... } virtual void foo2() { // do ... } };
像上面的代碼,若是類Person
就一直被實例化使用,可是沒有類去繼承它的話,那麼這個virtual
實際上並無什麼卵用。foo2()
方法和foo1()
是同樣的。小程序
當它被繼承的時候,有兩種狀況,覆寫(override)這個foo2()
方法,或者不覆寫它。好比這樣:ide
class Student : public Person { public: void foo2() { // do something.. } }; class Teacher : public Person { public: // no override };
而後咱們使用的時候,若是是子類的實例,調用foo2()
方法,理所固然是執行子類中所定義的foo2()
方法體。可是當將這個子類的實例強制轉型成父類的實例(指針),再去執行foo2()
方法的時候,對應的兩種狀況:子類實現了父類中virtual
方法的,調用子類的方法;子類中沒有override
的,仍然是調用父類中的實現(這不是廢話麼……)ui
列個表格大概是這樣:指針
// 大前提是父類中有個`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自帶這個多態的特性,不須要用什麼關鍵字修飾,某個實例轉換成父類後調用方法,默認就會調用子類的實現(若是有的話)。寫了個小demo實驗了一下,果真如此。code
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<String> strList = new ArrayList<String>(); //這樣是耿直的寫法 List<String> strList = new ArrayList<String>(); //這樣更好,由於你能夠換後面這個new // 返回值和參數也是同樣,通常能使用接口就儘可能使用接口,而不要寫死成實現類,這樣帶來更大的靈活性 public List<String> buildStrList(List<String> raw, AnyInterface interf) { // do xxxx }
virtual
關鍵字修飾的方法在子類繼承實現後,就能夠達到多態的目的(使用父類的指針依然能夠調用到子類的實現)。文檔
Java中不須要這個關鍵字來達到多態,覆寫方法自帶這個功能。