問題タブ [non-virtual-interface]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票する
2 に答える
609 参照

c# - C# の非仮想メソッド、静的バインディング、およびインターフェイス

非仮想メソッドは静的にバインドされていることを理解しています。つまり、私が理解している限りでは、どのメソッドがどのオブジェクトで呼び出されるかについて、コンパイル時にそれ自体が認識されていることを意味します。この決定は、オブジェクトの静的タイプに基づいて行われます。私を混乱させているのは、( classではなく)インターフェイスと静的バインディングです。

このコードを考えてみましょう。

デモコード: http://ideone.com/JOVmi

を理解していLine 1ます。コンパイラは、 の静的型が であることを知っているため、b.f()が呼び出されることを知ることができます。B.f()bB

しかし、コンパイラはコンパイル時にどのようia.f()に を呼び出すかをどのように決定するのA.f()でしょうか? オブジェクトの静的タイプは何iaですか? そうじゃないIA?しかし、それはインターフェースであり、の定義はありませんf()。では、なぜそれが機能するのですか?

ケースをより不可解にするために、次のstatic方法を考えてみましょう。

コメントにあるように、インターフェイスを実装するクラスが多すぎる可能性があります。その場合、どのメソッドを呼び出すかをIAコンパイルで静的に決定するにはどうすればよいでしょうか? ia.f()つまり、次のように定義されたクラスがあるとします。

ご覧のとおりC、 は とは異なり、からの派生に加えてB実装しています。つまり、ここでは動作が異なります。IAA

デモコード : http://ideone.com/awCor

これらすべてのバリエーション、特にインターフェイスと静的バインディングがどのように連携するかを理解するにはどうすればよいでしょうか?

さらにいくつか ( ideone ):

これらすべてと、C# コンパイラによって静的バインディングがどのように行われるかを理解するのを手伝ってください。

0 投票する
1 に答える
173 参照

c++ - 非仮想インターフェイスのイディオムを使用して、非仮想関数をインライン化できますか?

私は最近、非仮想インターフェイス イディオム (NVI) を使用して C++ でインターフェイスを設計することにしました。主な目的は、デフォルト値を持つパラメーターを使用することです (したがって、デフォルト パラメーターが静的にバインドされているという事実によって引き起こされる問題を回避します)。

私は自分のクラスに次のようなかなり些細な宣言をしました:

ヘッダーに関数本体を指定すると、関数がインライン化の候補として自動的にマークされることはわかっています (ただし、定義をクラスの外に配置するとそれが妨げられるかどうかはわかりません)。また、明らかな理由で仮想関数がインライン化されていないことも知っています (実行時にどの関数が呼び出されるかわからないため、明らかに関数の本体による呼び出しを置き換えることはできません)。

次に、この場合、func()インライン化の候補としてマークされますか? これは仮想関数ではありませんが、仮想関数を呼び出します。インライン化できますか?

追加の質問: それだけの価値はありますか? 本体は 1 つのステートメントのみで構成されます。

この質問は、どこでも最適化を検索するのではなく、それについて学ぶためのものであることに注意してください。私は、この関数が数回しか呼び出されないことを知っています (まあ、今のところ、プログラムがどのように進化するかについては賢明かもしれません)。

ありがとう !

0 投票する
1 に答える
110 参照

inheritance - プライベート継承と非仮想インターフェイス

それで、私はしばらく前から D に興味があり、少し前にいじりました。私はそれをもう一度見始めましたが、それが達成しようとしていることは本当に気に入っていますが、私のお気に入りの C++ 設計オプションの 1 つである非仮想インターフェイスについては懸念があります。

この設計で私が気に入っているのは、継承の階層の「最上位」で発生する前後の条件チェック、ロギング、およびリソース管理を可能にすることです。これにより、設計者は、関連するクラスのグループのすべての共通機能を指定し、クラスのカスタマイズ可能な部分を非常に小さな関数に分割できます。また、サブクラスに記述する必要がある機能の量も削減されます。さらに、仮想拡張ポイントはプライベートであるため、インターフェースを汚染したり、ユーザーが実装固有の関数を直接呼び出したりすることはありません (これが重要です)。

Dでこれを達成する方法はありますか?

C++ での例 (未テスト、未コンパイル...説明用)。

0 投票する
2 に答える
142 参照

c++ - 非仮想インターフェイスのイディオムに不変条件を追加する

NVI イディオムを使用して次の階層があるとします。

階層のある時点で、非仮想基本メソッドに不変条件を「追加」したい場合、最善の方法は何ですか?

1 つの方法は、SpecialBase レベルで NVI イディオムを再帰することです。

しかし、階層に追加する派生ベースごとに (異なる名前の) メソッドを追加したくないので、このアイデアはあまり好きではありません...

別の方法は、次のものを用意することです (これは NVI ではありません)。

私の意見では、具象クラスはいつでも仮想メソッドを実装する必要があるだけなので、混乱は少ないと思いますが、派生基本クラスも選択した場合は基本 (仮想) メソッドをオーバーライドできます。

同じことを達成するための別のよりクリーンな方法はありますか?

編集:

次のような階層を持つことができる非常に一般的な設計パターンを探しています。

Baseクラスは foo をオーバーライドできますが、クラスA-Fは再実装するだけで済みますfoo_impl

別のオプションのカスタマイズ仮想関数 (例: bar_impl) を追加するだけでは、ここでは役に立たないことに注意してください。

0 投票する
2 に答える
1219 参照

java - Android アクティビティのライフ サイクル: 最初にスーパー メソッドを呼び出さないのはなぜですか?

(Google ドキュメントによると) 基本的な Android 開発の要件の 1 つは、アクティビティのライフサイクル メソッド (onCreate、onResume、onPause など) をオーバーライドするときは、最初に親のメソッドを呼び出す必要があることです。

Android API が非仮想インターフェイス パターンを使用してこの動作を強制しないのはなぜですか?:

Android の Activity Base クラスは次のようになります (粗い例):

Android 開発者が作成した子クラス:

スーパー メソッドを呼び出す前に命令を記述する必要があるケースに遭遇したことはありません。スーパーメソッドを呼び出してはいけない、または最初に呼び出さないでください。ライフ サイクルの特定のメソッドで常に最初でなければならない場合、それを強制するために NVI パターンを使用しないという設計上の決定の背後にある理由は何でしたか?

更新: しばらくの間 Android 向けの開発を行ってきましたが、職場の全員が私の BaseActivity NVI クラスを使用していますが、すべてのライフサイクル メソッドではなく onCreate メソッドで NVI を使用しない理由にまだ遭遇していません。既存のAPI設計を擁護して回答/コメントした人は、本当に正当化されていないか、NVIパターンが何であるかを本当に理解していないように見えるので、私は良いことはないと仮定して行きます理由は、「そのまま」だからです。

0 投票する
2 に答える
148 参照

c++ - 非仮想インターフェースとマルチレベル継承を組み合わせる

Non-virtual Interface idiome (NVI) はかなり自明です:public virtual関数を書くのではなく、次のように実装関数publicを呼び出す関数を記述します。private virtual

これにより、基本クラスの作成者は、事前条件と事後条件をチェックして適用したり、他の関数を適用したりして、派生クラスの作成者がそれらを忘れないようにすることができます。

あなたが派生作成者である場合、基本クラスを自分で書きたいと思うかもしれません - それを呼びましょうPawn- それは の機能を拡張するload()ため、オーバーライドする必要がありますv_load()。しかし今、あなたは問題に直面しています:

をオーバーライドv_load()すると、クラスから派生したい他のクライアントは常にその動作を上書きしPawn::v_load()private関数であるため呼び出すことも、もちろん無限ループにつながるようにPawn::load()定義されているため呼び出すこと{ v_load; }もできませんObject. さらに、そうするように要求すると、その呼び出しを忘れたときにミスが発生する可能性があります。それを有効にしたい場合は、へのアクセスを のように指定する必要v_load()protectedありObjectますObject

v_load()もちろん、新しい関数を呼び出すためにオーバーライドすることもできますv_pawnLoad()。これはクライアントによってオーバーライドされますが、多くのクライアントが間違った関数をオーバーロードする可能性があるため、エラーが発生しやすいようです。

では、前提条件をチェックしたり、他の関数を呼び出したり、(可能であれば) 有効にせずに、クライアントに要求したり、基本実装を呼び出したりする機能を維持しながらPawn、クライアントがオーバーライドできるように設計するにはどうすればよいでしょうか?v_load()ObjectPawnv_load()

0 投票する
0 に答える
222 参照

c++ - 非仮想インターフェイスを自動的にラップして仮想化する C++ クラス テンプレートを作成することは可能ですか?

問題

単体テストを書くとき、モック オブジェクトが必要になることがよくあります。製品オブジェクトを置き換え可能にするために、モック オブジェクト クラスは製品オブジェクト クラスから派生し、いくつかの仮想関数をオーバーライドします。

本番クラスに仮想機能がなく、それを変更する権限がない場合に問題が発生します。今のところ、問題を解決するための 2 つの選択肢があります。

  1. クラスを、サブシステム タイプによってパラメーター化されたクラス テンプレートに変換します。あなたの生産クラスはMyClass<ProductionSubsystem>、テストのために使用されますMyClass<MockSubsystem>

  2. ラップされたサブシステム クラスの非仮想関数を呼び出す仮想関数を含むラッパーを手動で記述します。次に、ラッパーをモックします。

2つのオプションのいずれにも完全に満足しているわけではありません. 1 は「単純な」クラスをクラス テンプレートに変換することを強制し、2 は多くのボイラー プレート コードを記述することを強制します。

そのため、非仮想クラスのラッパーを作成するプロセスを自動化できるかどうか疑問に思っていました。私は次のようなものを想像します:

このセットアップでは、次のユース ケースが可能になります。

質問

C++ で AutoWrapper と AutoWrapperImpl の 2 つのクラスを実装することは可能ですか? もしそうなら、それはどのように行われ、公開されている解決策はありますか?

0 投票する
0 に答える
101 参照

c++ - マルチレベル NVI の仮想テンプレートの回避策

私が行っているプラ​​イベートプロジェクトでシリアライズしたいタイプの基本クラスとして機能するクラスを構築しようとしています。

「<<」と「>>」の機能を提供することで、少なくともシリアル化アーカイブと QDataStream をブーストしてクラスを機能させようとしています。クラスで動作する他のストリームは単なるボーナスです。

重要: 私はおそらく QDataStream のみを使用します。私はこのクラスをパズル/学習の機会として構築しています(これは機能しているようです)。したがって、この形式から完全に逸脱する回避策も歓迎しますが、私が望むように物事が機能することを非常に望んでいます(もちろん、言語の制限を考慮して可能な限り近い)、途中である程度の知識を得る.

私が思っていたクラスは次のようになります。

仮想テンプレートが許可されていないことをすぐに発見し、(私にとって) 新しい用語「タイプ消去」に適合しました。

この記事を読んだ後、型消去を採用しようとしました: C++ におけるオブジェクト指向プログラミングとジェネリック プログラミングの間の緊張と、それについて型消去ができること(「Beyond boost::any」まで)...

失敗しました。

いくつかのメモ:

Serializable_save と Serializable_load は、継承を下ってマルチレベル NVI を可能にする命名規則の一部です。 (マルチレベル NVI は、基本クラスから継承された仮想関数をファイナライズし、継承者に新しい仮想関数を提供するという概念に対して私が付けた名前にすぎません。一連のアクションが常に継承チェーン全体で実行されるようにします )最終クラスではない継承クラスは次のようになります。

私の次の試みは、「アーカイブ」テンプレートを StreamWrapper クラス内に埋め込むことでした (型消去に似ていますが、完全ではありません)。これにより、テンプレートの差し迫った必要性を排除し、仮想テンプレートの無限の問題に関するコンパイラの禁止事項を渡します。

もちろん、それはうまくいきませんでした。テンプレートの種類を指定する必要が生じたので、これは私が達成しようとしていたものとは正反対です。

重要な場合は C++14 を使用しています (つまり、11 から 14 の間)。

私はまだ Type Erasure が答えだと思っています。使い方がわかりません。

そう、

  • 私が望む動作を達成することは可能ですか? もし、そうなら:
  • 仮想テンプレートが違法な場合に、この「マルチレベル NVI」動作を許可するクラスを実現するにはどうすればよいですか?

編集:これは解決策になる と思いますが、まだ適切にテストできません。