本篇內(nèi)容介紹了“Java和C++中子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪問(wèn)性縮小的區(qū)別介紹”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)公司是一家專(zhuān)業(yè)提供城西企業(yè)網(wǎng)站建設(shè),專(zhuān)注與成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、HTML5、小程序制作等業(yè)務(wù)。10年已為城西眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專(zhuān)業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進(jìn)行中。
前言
“Java 和 C++ 中子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪問(wèn)性縮小的問(wèn)題”的題目看起來(lái)比較學(xué)術(shù)化,但的確是一個(gè)容易忽視的問(wèn)題。本文力求詳細(xì)闡述這一問(wèn)題在 Java 以及 C++ 中的區(qū)別。
先介紹什么是“子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪問(wèn)性縮小”。對(duì)于繼承而言,子類(lèi)可以覆蓋父類(lèi)的“虛函數(shù)”——盡管 Java 中沒(méi)有虛函數(shù)這一術(shù)語(yǔ),但可以把 Java 的所有函數(shù)都看作虛函數(shù),因?yàn)?Java 的所有函數(shù)都可以被子類(lèi)覆蓋。這里僅借用“虛函數(shù)”這一名詞的含義,不深究語(yǔ)言的細(xì)節(jié)。Java 和 C++ 都允許在覆蓋時(shí),改變函數(shù)的可訪問(wèn)性。所謂“可訪問(wèn)性”,就是使用 public 、 protected 、 private 等訪問(wèn)控制符進(jìn)行修飾,用來(lái)控制函數(shù)能否被訪問(wèn)到。通常可訪問(wèn)性的順序?yàn)椋ㄓ捎?C++ 中沒(méi)有包的概念,因此暫不考慮包訪問(wèn)控制符,這并不影響這里的討論):
public > protected > private
以 Java 為例:
class Base { protected void sayHello() { System.out.println("Hello in Base"); } } class Child extends Base { public void sayHello() { System.out.println("Hello in Child"); } }
注意:這里的 sayHello()
函數(shù)。父類(lèi) Base 中,該函數(shù)使用 protected 訪問(wèn)控制符進(jìn)行修飾。而子類(lèi)將其改用 public ,這不會(huì)有任何問(wèn)題。 子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋時(shí),擴(kuò)大可訪問(wèn)性,通常都不是問(wèn)題。
當(dāng)子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪問(wèn)性縮小時(shí),Java 和 C++ 采取了不同的策略。
首先以 Java 為例,看下面的代碼:
class Base { public void sayHello() { System.out.println("Hello in Base"); } } class Child extends Base { private void sayHello() { System.out.println("Hello in Child"); } }
上面的代碼中,高亮的第 8 行會(huì)有編譯錯(cuò)誤——這段代碼根本不能通過(guò)編譯! Java 不允許子類(lèi)在覆蓋父類(lèi)函數(shù)時(shí),縮小可訪問(wèn)性。 至于原因,我們可以用一個(gè)例子來(lái)說(shuō)明。例如我們?cè)陬?lèi)外部寫(xiě)下面的代碼:
Base base = new Base(); base.sayHello(); base = new Child(); base.sayHello();
假如之前的代碼可以通過(guò)編譯,那么就存在這么一種可能:當(dāng) base 指向 new Base() 時(shí), sayHello() 是可以訪問(wèn)到的,但是當(dāng) base 指向 new Child() 時(shí), sayHello() 卻無(wú)法訪問(wèn)到!在 Java 看來(lái)這是一個(gè)矛盾,應(yīng)該避免出現(xiàn)這種問(wèn)題,因此,Java 從編譯器的角度規(guī)定我們不能寫(xiě)出上面的代碼。
針對(duì) C++,情況又有所區(qū)別。來(lái)看 C++ 的例子:
class Base { public: virtual void sayHello() { std::cout << "Hello in Base"; } } class Child : public Base { private: void sayHello() { std::cout << "Hello in Child"; } }
這段代碼在 C++ 中是完全正確的。注意,這里的子類(lèi)在覆蓋父類(lèi)函數(shù)時(shí), 縮小 了可訪問(wèn)性。如果你沒(méi)有看出有什么問(wèn)題,那么我們完全可以在類(lèi)外部寫(xiě)出下面的代碼:
Child child; child.sayHello(); // 不能通過(guò)編譯,因?yàn)?nbsp;sayHello() 是 private 的 static_cast<Base&>(child).sayHello(); // 可以通過(guò)編譯,因?yàn)?nbsp;sayHello() 是 public 的
第 2 行調(diào)用是失敗的,因?yàn)樵?Child 中, sayHello()
是 private 的,不能在外部調(diào)用。然而,當(dāng)我們使用 static_cast 將 Child 強(qiáng)制轉(zhuǎn)換成 Base 對(duì)象時(shí),事情發(fā)生了改變——對(duì)于 Base 而言, sayHello()
是 public 的,因此可以正常調(diào)用。
針對(duì)這一點(diǎn),C++ 標(biāo)準(zhǔn)的 Member access control 一章中的 Access to virtual functions 一節(jié)可以找到如下的例子:
class B { public: virtual int f(); }; class D : public B { private: int f(); }; void f() { D d; B* pb = &d; D* pd = &d; pb->f(); // OK: B::f() is public, D::f() is invoked pd->f(); // error: D::f() is private }
對(duì)此,C++ 標(biāo)準(zhǔn)給出的解釋是:
Access is checked at the call point using the type of the expression used to denote the object for which the member function is called ( B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.
簡(jiǎn)單翻譯過(guò)來(lái)有兩條要點(diǎn):
訪問(wèn)控制是在調(diào)用時(shí)檢查的,也就是說(shuō),誰(shuí)調(diào)用了這個(gè)函數(shù),就檢查誰(shuí)能不能訪問(wèn)這個(gè)函數(shù)
類(lèi)中成員函數(shù)的可訪問(wèn)性一般而言是不知道的,也就是說(shuō),檢查可訪問(wèn)性時(shí),并不能知道這個(gè)函數(shù)在定義時(shí)到底是 public 的還是 private 的,因此也就無(wú)法據(jù)此檢查可訪問(wèn)性
正因如此,C++ 的調(diào)用方似乎可以通過(guò)一些技巧性轉(zhuǎn)換,“巧妙地”調(diào)用到原本無(wú)法訪問(wèn)的函數(shù)。一個(gè)更加實(shí)際的例子是:Qt 里面, QObject::event()
函數(shù)是 public ,而其子類(lèi) QWidget 的 event()
函數(shù)則改變成 protected 。具體可以閱讀 Qt 的相關(guān)代碼。
總結(jié)來(lái)說(shuō),在子類(lèi)覆蓋父類(lèi)函數(shù)時(shí),Java 嚴(yán)格限制了子類(lèi)不能縮小函數(shù)可訪問(wèn)性,但 C++ 無(wú)此限制。個(gè)人認(rèn)為,從軟件工程的角度來(lái)說(shuō),Java 的規(guī)定無(wú)疑更具有工程上面的意義,函數(shù)的調(diào)用也更加一致。C++ 的標(biāo)準(zhǔn)則會(huì)明顯簡(jiǎn)化編譯器實(shí)現(xiàn),但是對(duì)工程而言并不算很好的參考。
“Java和C++中子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪問(wèn)性縮小的區(qū)別介紹”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
網(wǎng)頁(yè)標(biāo)題:Java和C++中子類(lèi)對(duì)父類(lèi)函數(shù)覆蓋的可訪問(wèn)性縮小的區(qū)別介紹
URL標(biāo)題:http://www.yijiale78.com/article2/piodoc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、自適應(yīng)網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司、域名注冊(cè)、品牌網(wǎng)站制作、App開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)