問題タブ [pimpl-idiom]
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.
c++ - クラスメンバー変数で使用される Pimpl イディオム
このクラスを実装する正しい方法は何ですか?
c++ - 列挙型定義から依存定数を削除する
不透明な構造と前方宣言を使用してプロジェクトから依存関係を安全に削除しようとしていますが、ほとんどの場合と同様に、まだ列挙型にこだわっています。
ヘッダー ファイルから削除しようとしているヘッダー ファイルの依存関係には、列挙の値を設定する定数が定義されています。このようなもの
ヘッダーに依存ヘッダーを含める必要がないようにする方法を見つけようとしています。
おそらく答えは単純に「そんなことはできない」でしょうが、解決策があれば私の人生は無限に楽になるので、質問したいだけです。
c++ - 最小限のコードで pImpl を実装する
pImpl クラスを実装する作業負荷を最小限に抑えるには、どのようなトリックを使用できますか?
ヘッダ:
実装:
Boost、おそらく継承、CRTP、またはその他のトリックを使用して、可能な限り多くの定型コードを回避して、これをどのように改善しますか? 実行時のパフォーマンスは問題ではありません。
c++ - pImpl イディオムとテスト容易性
c++ の pImpl イディオムは、クラスのユーザーからクラスの実装の詳細 (= プライベート メンバー) を隠すことを目的としています。ただし、テストの観点から通常は悪いと見なされる、そのクラスの依存関係の一部も隠します。
たとえば、クラス A が、A.cpp からのみアクセスできるクラス AImpl にその実装の詳細を隠し、AImpl が他の多くのクラスに依存している場合、テスト フレームワークがクラス A のメソッドにアクセスできないため、クラス A の単体テストが非常に困難になります。 AImpl に依存関係を注入する方法もありません。
誰もこの問題に遭遇したことがありますか? 解決策を見つけましたか?
- 編集 -
関連するトピックでは、内部ではなく、インターフェイスによって公開されたパブリック メソッドのみをテストする必要があると人々が提案しているようです。そのステートメントを概念的に理解することはできますが、プライベート メソッドを個別にテストする必要があることがよくあります。たとえば、パブリック メソッドが重要なロジックを含むプライベート ヘルパー メソッドを呼び出す場合などです。
c++ - C++ pimpl イディオムは命令と C スタイルを無駄にしますか?
(はい、通常は 1 つの機械語命令は問題にならないことを知っています。私がこの質問をするのは、pimpl のイディオムを理解し、可能な限り最良の方法で使用したいからです。また、1 つの機械語命令を気にすることもあるためです。 )
以下のサンプル コードには、 と の 2 つのクラスがThing
あり
OtherThing
ます。ユーザーは「thing.hh」を含めます。
Thing
pimpl イディオムを使用して実装を隠します。
OtherThing
C スタイル (ポインターを返したり受け取ったりする非メンバー関数) を使用します。このスタイルは、わずかに優れたマシン コードを生成します。私は疑問に思っています: C++ スタイルを使用する方法 (つまり、関数をメンバー関数にする方法) はありますか? クラス外の名前空間を汚染しないので、このスタイルが気に入っています。
注: メンバー関数の呼び出しのみを検討しています (この場合はcalc
)。オブジェクトの割り当ては見ていません。
以下は、私の Mac 上のファイル、コマンド、およびマシン コードです。
こと.hh:
事.cc:
main.cc (コードが実際に動作することをテストするためだけに...)
メイクファイル:
make
マシンコードを実行して見てください。私が使用するMacでotool -tv thing.o | c++filt
。Linux ではobjdump -d thing.o
. 関連する出力は次のとおりです。
Thing :: calc(): 0000000000000000
MOVQ(%RDI)、%
RAX 00000000000003 MOVL(%RAX )、%EAX 0000000000000005 INPLECT EAX 0000000000000007 RET CALC(その他): 00000000000010 MOVL(%RDI) 0000000000000014 ret
ポインタの間接化による余分な命令に注意してください。最初の関数は 2 つのフィールド (impl、次に x) を検索しますが、2 番目の関数は x を取得するだけで済みます。何ができるでしょうか?
c++ - プライベート パーツへの委任
ときどき、C++ のプライバシーの概念に当惑することがあります :-)
Foo::Bar
ですので、private
では宣言できません。それでも、問題なくメソッドを呼び出すことができます。なんでこんなの許されるの?それは偶然ですか、それとも意図的なものですか?b
main
Foo::Bar
ちょっと待ってください。
type に名前を付けることは許可されていませんが、 ...Foo::Bar
で問題なく動作します。auto
ノアは次のように書いています。
クラス定義内で定義された型名は、修飾せずにクラス外で使用することはできません。
楽しみのために、外部から型を取得する方法を次に示します。
c++ - プライベート部分をC ++ヘッダーの外に保持する:純粋な仮想基本クラスとpimpl
私は最近、Java と Ruby から C++ に切り替えましたが、驚いたことに、プライベート メソッドのメソッド シグネチャを変更すると、パブリック インターフェイスを使用するファイルを再コンパイルする必要があります。これは、プライベート部分も .h ファイルにあるためです。
私はすぐに、おそらく Java プログラマーにとって典型的な解決策、つまりインターフェース (= 純粋仮想基底クラス) を思いつきました。例えば:
BananaTree.h:
BananaTree.cpp:
ここでの唯一の問題は、 を使用できずnew
、代わりに を呼び出さなければならないことBananaTree::create()
です。とにかく工場をたくさん使うことを期待しているので、それは本当に問題ではないと思います。
しかし、C++ で有名な賢者たちは、別の解決策pImpl イディオムを思い付きました。それで、正しく理解できれば、私のコードは次のようになります。
BananaTree.h:
BananaTree.cpp:
これは、 のすべてのパブリック メソッド (BananaTree
この場合は ) に対して、デコレータ スタイルの転送メソッドを実装する必要があることを意味しgetBanana
ます。これは、私が要求したくない複雑さとメンテナンスの労力の追加レベルのように思えます。
では、ここで質問です。純粋仮想クラスのアプローチの何が問題なのですか? pImpl アプローチのほうが文書化されているのはなぜですか? 何か見逃しましたか?
c++ - これは PIMPL パターンを使用するのに適した場所ですか?
一部のサービスのクライアント インターフェイスを定義するライブラリに取り組んでいます。内部では、ユーザーから提供されたデータを検証し、別のライブラリの Connection クラスを使用して「エンジン」プロセスに渡す必要があります (注: Connection クラスはライブラリのユーザーには知られていません)。私の同僚の 1 人が PIMPL の使用を提案しました。
ただし、テストするのは非常に難しいと思います。テストを接続の模擬実装にリンクしたとしても、期待を設定して検証するために簡単にアクセスすることはできません。私は何か不足していますか、それともよりクリーンでテスト可能なソリューションは、インターフェイス + ファクトリを使用しています:
この状況で PIMPL を使用する理由はありますか?
c++ - PIMPL とスタック割り当て
そこで、PIMPL とスタック割り当てについて考えてみました。私はライブラリを作成しており、PIMPL を使用してクラスのプライベート メンバーを非表示にすることにしました。つまり、このようにクラスを宣言することになります
それはかなり簡単です。しかし、コンストラクターでこれを行います
したがって、誰かが私のライブラリを使用してスタックに Foo を作成する場合、基本的にヒープ割り当てを行っています。これは、PIMPL を使用する際に考慮しなければならないトレードオフですか? コンストラクターの横に警告を表示してドキュメントをリリースすることを考えました:「警告: これにより、ヒープ割り当てが発生します」など。
私のもう 1 つの考えは、純粋な仮想インターフェイスとして実装に公開されるすべてのクラスと、スマート ポインターを返す一連の静的ファクトリ メソッドを用意することでした。これはヒープ割り当ても意味しますが、トリックはありません。
何か考えや提案はありますか?ライブラリを使用するプログラマーに対して、私は過度に配慮していませんか?
c++ - pimpl イディオムはどのように依存関係を減らしますか?
次の点を考慮してください。
PImpl.hpp
PImpl.cpp
実装.hpp
client.cpp
このパターンの背後にある考え方は、Impl
のインターフェースは変更できますが、クライアントを再コンパイルする必要はないというものです。しかし、これが実際にどのように当てはまるのか、私にはわかりません。このクラスにメソッドを追加したいとしましょう。クライアントはまだ再コンパイルする必要があります。
基本的に、クラスのヘッダー ファイルを変更する必要があると思われるこのような変更は、クラスのインターフェイスが変更されるものだけです。そして、それが発生した場合、pimpl の有無にかかわらず、クライアントは再コンパイルする必要があります。
クライアント コードを再コンパイルしないという点で、ここでどのような種類の編集を行うとメリットがありますか?