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