中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java和C++中子類對父類函數覆蓋的可訪問性縮小的區別介紹

發布時間:2021-09-06 17:37:49 來源:億速云 閱讀:115 作者:chen 欄目:編程語言

本篇內容介紹了“Java和C++中子類對父類函數覆蓋的可訪問性縮小的區別介紹”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

前言

“Java 和 C++ 中子類對父類函數覆蓋的可訪問性縮小的問題”的題目看起來比較學術化,但的確是一個容易忽視的問題。本文力求詳細闡述這一問題在 Java 以及 C++ 中的區別。

先介紹什么是“子類對父類函數覆蓋的可訪問性縮小”。對于繼承而言,子類可以覆蓋父類的“虛函數”——盡管 Java 中沒有虛函數這一術語,但可以把 Java 的所有函數都看作虛函數,因為 Java 的所有函數都可以被子類覆蓋。這里僅借用“虛函數”這一名詞的含義,不深究語言的細節。Java 和 C++ 都允許在覆蓋時,改變函數的可訪問性。所謂“可訪問性”,就是使用 public 、 protected 、 private 等訪問控制符進行修飾,用來控制函數能否被訪問到。通常可訪問性的順序為(由于 C++ 中沒有包的概念,因此暫不考慮包訪問控制符,這并不影響這里的討論):

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() 函數。父類 Base 中,該函數使用 protected 訪問控制符進行修飾。而子類將其改用 public ,這不會有任何問題。 子類對父類函數覆蓋時,擴大可訪問性,通常都不是問題。

當子類對父類函數覆蓋的可訪問性縮小時,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 行會有編譯錯誤——這段代碼根本不能通過編譯! Java 不允許子類在覆蓋父類函數時,縮小可訪問性。 至于原因,我們可以用一個例子來說明。例如我們在類外部寫下面的代碼:

Base base = new Base();
base.sayHello();
base = new Child();
base.sayHello();

假如之前的代碼可以通過編譯,那么就存在這么一種可能:當 base 指向 new Base() 時, sayHello() 是可以訪問到的,但是當 base 指向 new Child() 時, sayHello() 卻無法訪問到!在 Java 看來這是一個矛盾,應該避免出現這種問題,因此,Java 從編譯器的角度規定我們不能寫出上面的代碼。

針對 C++,情況又有所區別。來看 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++ 中是完全正確的。注意,這里的子類在覆蓋父類函數時, 縮小 了可訪問性。如果你沒有看出有什么問題,那么我們完全可以在類外部寫出下面的代碼:

Child child;
child.sayHello(); // 不能通過編譯,因為 sayHello() 是 private 的
static_cast<Base&>(child).sayHello(); // 可以通過編譯,因為 sayHello() 是 public 的

第 2 行調用是失敗的,因為在 Child 中, sayHello() 是 private 的,不能在外部調用。然而,當我們使用 static_cast 將 Child 強制轉換成 Base 對象時,事情發生了改變——對于 Base 而言, sayHello() 是 public 的,因此可以正常調用。

針對這一點,C++ 標準的 Member access control 一章中的 Access to virtual functions 一節可以找到如下的例子:

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
}

對此,C++ 標準給出的解釋是:

 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.

簡單翻譯過來有兩條要點:

  • 訪問控制是在調用時檢查的,也就是說,誰調用了這個函數,就檢查誰能不能訪問這個函數

  • 類中成員函數的可訪問性一般而言是不知道的,也就是說,檢查可訪問性時,并不能知道這個函數在定義時到底是 public 的還是 private 的,因此也就無法據此檢查可訪問性

正因如此,C++ 的調用方似乎可以通過一些技巧性轉換,“巧妙地”調用到原本無法訪問的函數。一個更加實際的例子是:Qt 里面, QObject::event() 函數是 public ,而其子類 QWidget 的 event() 函數則改變成 protected 。具體可以閱讀 Qt 的相關代碼。

總結來說,在子類覆蓋父類函數時,Java 嚴格限制了子類不能縮小函數可訪問性,但 C++ 無此限制。個人認為,從軟件工程的角度來說,Java 的規定無疑更具有工程上面的意義,函數的調用也更加一致。C++ 的標準則會明顯簡化編譯器實現,但是對工程而言并不算很好的參考。

“Java和C++中子類對父類函數覆蓋的可訪問性縮小的區別介紹”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海盐县| 麟游县| 天长市| 冕宁县| 理塘县| 清远市| 海安县| 吐鲁番市| 宁陕县| 曲靖市| 来凤县| 麻城市| 乌拉特前旗| 浦江县| 始兴县| 晴隆县| 英超| 宝山区| 宁德市| 涞水县| 松潘县| 天水市| 黄骅市| 庐江县| 蓬莱市| 永平县| 洪洞县| 浙江省| 横峰县| 昌吉市| 临洮县| 商水县| 仙桃市| 长春市| 龙里县| 神农架林区| 盖州市| 皋兰县| 广昌县| 彰化市| 祁东县|