44

C# にはプライベート/保護された継承の概念がありますか?そうでない場合、その理由は?

C++


class Foo : private Bar {
 public:
   ...
 }; 

C#


public abstract NServlet class : private System.Web.UI.Page
{
    // error "type expected"
}

.aspx ページに「サーブレットのような」概念を実装していますが、具象クラスが System.Web.UI.Page ベースの内部を参照できるようにしたくありません。

4

10 に答える 10

20

C# では、パブリック継承のみが許可されます。C++ では 3 種類すべてが許可されていました。パブリック継承は「IS-A」タイプの関係を意味し、プライベート継承は「Is-Implemented-In-Term-Of」タイプの関係を意味していました。層化 (または合成) がこれをおそらくより単純な方法で実現したため、プライベート継承は、保護されたメンバーによって絶対に必要な場合、または仮想関数がそれを必要とする場合にのみ使用されました。

私の推測では、C# の作成者は、あるクラスを別のクラスに関して実装するこの追加の方法が必要だとは感じていなかったと思います。

于 2008-08-28T19:30:30.787 に答える
8

いいえ、そうではありません。この種の制限を許可する利点は何ですか?

プライベートで保護された継承は、カプセル化 (情報の隠蔽) に適しています。Protected* 継承は C++ でサポートされていますが、Java ではサポートされていません。これが役立つ私のプロジェクトの例です。

サードパーティのフレームワークとしてベース クラスがあります**。多数の設定に加えて、それらを操作するためのプロパティとメソッドがあります。基本クラスは、個々の設定が割り当てられたときに多くのチェックを行いませんが、受け入れられない組み合わせに遭遇すると、後で例外を生成します。

これらの設定を割り当てるためのメソッドを持つ子クラスを作成しています (たとえば、慎重に作成された設定をファイルから割り当てるなど)。コードの残りの部分 (子クラス以外) が個々の設定を操作して台無しにする機能を拒否するとよいでしょう。

そうは言っても、C++ (これもプライベートおよび保護された継承をサポートしています) では、子クラスを親にキャストし、親のパブリック メンバーにアクセスできると思います。( Chris Karcher の投稿も参照してください) それでも、保護された継承により、情報の隠蔽が改善されます。クラス B1 のメンバーを他のクラス C1 および C2 内に完全に隠す必要がある場合は、C1 および C2 内にクラス B1 の保護変数を作成することによって配置できます。B1 の保護されたインスタンスは、C1 と C2 の子で使用できます。もちろん、このアプローチだけでは、C1 と C2 の間のポリモーフィズムは提供されません。ただし、(必要に応じて) 共通のインターフェイス I1 から C1 と C2 を継承することにより、ポリモーフィズムを追加できます。

*** 簡潔にするために、「プライベートおよび保護」の代わりに「保護」を使用します。

**私の場合はNational Instruments Measurement Studioです。

  • ニック
于 2010-02-23T21:05:57.210 に答える
5

クラス内で同じメンバーをプライベートとして宣言し、new キーワードを使用することで、継承された API が公開されないようにすることができます。MSDNからの継承による非表示を参照してください。

于 2008-08-28T19:11:55.963 に答える
3

NServlet クラスが Page について何も認識しないようにする場合は、Adapter パターンの使用を検討する必要があります。NServlet クラスのインスタンスをホストするページを作成します。正確に何をしているかに応じて、asp.net ページ メンバーで API を汚染することなく、基本クラス NServlet についてのみ知っているさまざまなクラスを作成できます。

于 2008-08-28T19:13:31.560 に答える
3

@bdukes:本当にメンバーを隠しているわけではないことに注意してください。例えば:

class Base
{
   public void F() {}
}
class Derived : Base
{
   new private void F() {}
}

Base o = new Derived();
o.F();  // works

しかし、これは質問者が望んでいた C++ のプライベート継承と同じことを実現します。

于 2008-08-28T19:30:45.170 に答える
1

いいえ、公開継承のみです。

于 2008-08-28T19:03:38.557 に答える
1

おそらく、NServlet 実装に接続される ServletContainer クラスが必要になるでしょう。私の本では、プライベート/保護された継承を許可しないことは実際には大したことではなく、言語の混乱を軽減します-LINQなどを使用すると、覚えておくべきことはすでに十分にあります。

于 2008-08-28T19:10:00.617 に答える
1

私はこれが古い質問であることを知っていますが、C# を書いているときにこの問題に何度か遭遇しました。

サード パーティ フレームワークのクラスのサブクラスを作成するときは、パブリック インターフェイスも実装します。次に、そのインターフェイスを定義して、クライアントにアクセスさせたいメソッドのみを含めます。次に、クライアントがそのクラスのインスタンスを要求したときに、代わりにそのインターフェイスのインスタンスを提供します。

これは、これらの種類のことを行う C# で受け入れられている方法のようです。

初めてこれを行ったのは、C# 標準ライブラリに辞書の読み取り専用バリアントがないことに気付いたときでした。ディクショナリへのアクセスを提供したかったのですが、ディクショナリ内の項目を変更する機能をクライアントに与えたくありませんでした。そこで、「class DictionaryEx<K,V,IV> : Dictionary<K,V>, IReadOnlyDictionary<K,IV> where V : IV」を定義しました。ここで、K はキー型、V は実数値型、IV は変更を防止する V タイプへのインターフェイス。DictionaryEx の実装は、ほとんど単純でした。唯一難しいのは ReadOnlyEnumerator クラスを作成することでしたが、それにもそれほど時間はかかりませんでした。

このアプローチの唯一の欠点は、クライアントがパブリック インターフェイスを関連するサブクラスに動的にキャストしようとする場合です。これを止めるには、クラスを internal にします。クライアントがパブリック インターフェイスを元の基本クラスにキャストした場合、自分の命を奪っていることは明らかだと思います。:-)

于 2012-06-23T17:15:07.240 に答える
1

最初の解決策:

protected internalは、同じアセンブリでパブリックとして機能し、他のアセンブリでは保護されています。

継承によって公開されないクラスの各メンバーのアクセス修飾子を変更する必要があります。

ただし、このソリューションでは、クラスを継承して別のアセンブリで使用する必要があり、強制することは少し制限的です。したがって、継承によってのみ使用されるかどうかの選択は、知らない親によって行われます...通常、子供はアーキテクチャをよりよく知っています...

完全な解決策ではありませんが、インターフェイスを追加してメソッドを非表示にし、親メソッドを使用して子クラスを非表示にする可能性を残すよりも優れた代替手段になる可能性があります。これは、インターフェイスの使用を簡単に強制できないためです。


問題:

protectedおよびprivateアクセス修飾子は、ingインターフェイスを実装するメソッドには使用できません。つまり、保護された内部ソリューションは、インターフェイスで実装されたメソッドには使用できません。これは大きな制限です。


最終的解決:

メソッドを非表示にするインターフェイスソリューションに戻りました。

それに関する問題は、非表示にするメンバーが常に非表示になり、間違いを確実に回避できるように、インターフェイスの使用を強制できることでした。

interface のみを強制的に使用するには、コンストラクターを保護し、構築用の静的メソッドを追加します(New という名前を付けました)。この静的な New メソッドは実際にはファクトリ関数であり、インターフェイスを返します。したがって、コードの残りの部分はインターフェイスのみを使用する必要があります。

于 2015-09-16T17:15:26.440 に答える
-3

いいえ、そうではありません。この種の制限を許可する利点は何ですか?

于 2008-08-28T19:11:40.083 に答える