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