序文
「JavaおよびC ++の親クラス関数に対するサブクラスのアクセシビリティを減らす問題」というタイトルは、より学術的なようですが、実際には無視しやすい問題です。この記事は、JavaとC ++のこの問題の違いについて詳しく説明するよう努めています。
まず、「親クラス機能カバレッジよりもサブクラスのアクセシビリティ削減」とは何かを紹介します。継承の場合、サブクラスは親クラスの「仮想関数」をオーバーライドできます - JavaにはすべてのJava関数は仮想関数と見なすことができます。ここでは、「仮想関数」という用語の意味のみを借りて、言語の詳細を掘り下げないでください。 JavaとC ++の両方が、上向きに機能のアクセシビリティを変更することを可能にします。いわゆる「アクセシビリティ」は、パブリック、保護、プライベートなどのアクセス制御キャラクターを使用して、機能にアクセスできるかどうかを制御することです。通常、アクセシビリティの順序は(C ++にパッケージの概念がないため、パッケージアクセス制御は当面ではないため、ここでの議論には影響しません):
public> protected> private
例としてJavaを取ります:
class base {protected void sayshello(){system.out.println( "hello in base"); }} class Child拡張base {public void sayshello(){system.out.println( "hello in child"); }}注: sayHello()機能はこちら。親クラスベースでは、この関数は保護されたアクセス制御文字を使用して変更されます。代わりにサブクラスが公開されているため、問題はありません。サブクラスが親クラス機能をオーバーライドする場合、通常、アクセシビリティの拡大は問題ではありません。
JavaとC ++は、サブクラスが親クラス関数のアクセシビリティオーバーライドを減らすと、さまざまな戦略を採用します。
まず、Javaを例に取り、次のコードを見てください。
クラスベース{public void sayshello(){system.out.println( "hello in base"); }} class Child extends base {private void sayshello(){system.out.println( "hello in child"); }}上記のコードでは、ハイライトされた行8にコンパイルエラーが発生します。このコードはまったくコンパイルできません! Javaは、親クラスの機能を上書きするときにサブクラスがアクセシビリティを減らすことを許可していません。理由については、例を使用して説明できます。たとえば、クラスの外に次のコードを書きます。
base base = new base(); base.sayhello(); base = new child(); base.sayhello();
以前のコードをコンパイルできる場合、ベースがnew base()を指すと、sayhello()にアクセスできる可能性がありますが、ベースがnew child()を指すと、sayhello()にアクセスできません! Javaの見解では、これは矛盾であり、この問題は避けるべきです。したがって、Javaは、上記のコードを書くことができないというコンパイラの観点から規定されています。
C ++の場合、状況は異なります。 C ++の例を見てみましょう。
クラスベース{public:virtual void sayshello(){std :: cout << "hello in base"; }} class Child:public Base {private:void sayshello(){std :: cout << "hello in child"; }}このコードはC ++で完全に正しいです。ここでのサブクラスは、親クラス機能を上書きするときにアクセシビリティを減らすことに注意してください。問題がわからない場合は、クラスの外に次のコードを書くことができます。
子供の子供; child.sayhello(); // sakehello()がstatic_cast <base &>(child).sayhello(); // sakehello()が公開されているため、コンパイルできません
Childでは、 sayHello()がプライベートであり、外部的に呼ばれることはできないため、2行目の呼び出しは失敗します。ただし、Static_castを使用して子供をベースオブジェクトにキャストすると、状況が変更されます。ベースの場合、 sayHello()は公開されるため、通常と呼ばれます。
この目的のために、次の例は、C ++標準メンバーのアクセス制御章の仮想関数セクションにアクセスしてください。
クラス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()がpd-> f()が呼び出されます。 //エラー:D :: F()はプライベートです}この点で、C ++標準は説明を示します。
アクセスは、メンバー関数が呼び出されるオブジェクトを示すために使用される式のタイプを使用して、コールポイントでチェックされます(上記の例ではb*)。それが定義されたクラスでのメンバー関数のアクセス(上記の例では)は一般に不明です。
簡単な翻訳には2つの重要なポイントがあります。
このため、C ++発信者は、元々熟練した変換を通じてアクセスできなかった関数を「巧妙に」呼び出すことができるようです。より実用的な例は、QTでは、 QObject::event()関数がpublicであり、そのサブクラスQWidget event()関数が保護されたものに変更されます。詳細については、QTの関連コードを読むことができます。
要約すると、サブクラスが親機能を上書きすると、Javaはサブクラスが機能アクセシビリティを絞り込むことができないことを厳密に制限しますが、C ++にはこの制限がありません。個人的には、ソフトウェアエンジニアリングの観点から見ると、Javaの規制は間違いなくエンジニアリングの重要性があり、機能の呼び出しがより一貫していると思います。 C ++標準は、コンパイラの実装を大幅に簡素化しますが、エンジニアリングの適切な参照ではありません。
PS: C ++標準の公式バージョンでは購入が必要ですが、ドラフトは無料でダウンロードできます。 C ++標準ドラフトのダウンロードアドレスは、次のページhttps://isocpp.org/std/the-standardにあります。
要約します
上記は、この記事のコンテンツ全体です。この記事の内容には、すべての人の研究や仕事に特定の参照値があることを願っています。ご質問がある場合は、メッセージを残してコミュニケーションをとることができます。 wulin.comへのご支援ありがとうございます。