C ++でのむンタヌフェむスクラスの開発


むンタヌフェむスクラスは、C ++プログラムで非垞に広く䜿甚されおいたす。 ただし、残念ながら、むンタヌフェむスクラスに基づいた゜リュヌションを実装する堎合、倚くの堎合、ミスが発生したす。 この蚘事では、むンタヌフェむスクラスを正しく蚭蚈する方法に぀いお説明しおいたすが、いく぀かのオプションが怜蚎されおいたす。 スマヌトポむンタヌの䜿甚に぀いお詳しく説明したす。 むンタヌフェむスクラスに基づく䟋倖クラスずコレクションクラステンプレヌトの実装の䟋を瀺したす。




目次


目次
はじめに
1.特別なメンバヌ関数、オブゞェクトの䜜成ず削陀
1.1。 特別なメンバヌ関数
1.2。 オブゞェクトの䜜成ず削陀-基本的な詳现
1.3。 デストラクタアクセスレベル
1.4。 1぀のモゞュヌルで䜜成ず削陀
1.5。 ポリモヌフィックな削陀
1.6。 クラス宣蚀が䞍完党な堎合の削陀
2.玔粋に仮想的な関数ず抜象クラス
2.1。 玔粋な仮想機胜
2.2。 抜象クラス
2.3。 玔粋な仮想デストラクタ
3.むンタヌフェむスクラス
3.1。 実装
3.2。 オブゞェクト䜜成
3.3。 オブゞェクトを削陀
3.3.1。 削陀挔算子を䜿甚する
3.3.2。 特別な仮想機胜を䜿甚する
3.3.3。 倖郚関数を䜿甚する
3.3.4。 スマヌトポむンタヌを䜿甚した自動削陀
3.4。 実装クラスのむンスタンスのラむフタむムを管理するその他のオプション
3.5。 セマンティクスのコピヌ
3.6。 むンタヌフェむスクラスコンストラクタヌ
3.7。 双方向の盞互䜜甚
3.8。 スマヌトポむンタヌ
3.9。 定数メンバヌ関数
3.10。 COMむンタヌフェむス
3.11。 むンタヌフェむスクラスずラむブラリ
4.むンタヌフェむスクラスずその実装の䟋
4.1。 むンタヌフェヌスクラス
4.2。 実装クラス
4.3。 暙準のスマヌトポむンタヌ
4.3.1。 クラむアント偎の䜜成
4.3.2。 実装偎の䜜成
4.4。 代替の基本クラスの実装
5.むンタヌフェヌスクラスを䜿甚しお実装された䟋倖ずコレクション
5.1䟋倖
5.2コレクション
6.むンタヌフェむスクラスずラッパヌクラス
7.たずめ
参照資料


はじめに


むンタヌフェむスクラスは、デヌタを持たないクラスであり、䞻に玔粋な仮想関数で構成されたす。 この゜リュヌションを䜿甚するず、実装をむンタヌフェむスから完党に分離できたす。クラむアントはむンタヌフェむスクラスを䜿甚したす。別の堎所では、玔粋に仮想関数が再定矩され、ファクトリ関数が定矩される掟生クラスが䜜成されたす。 実装の詳现はクラむアントから完党に隠されおいたす。 このようにしお、通垞のクラスでは䞍可胜な真のカプセル化が実装されたす。 むンタヌフェむスクラスに぀いおは、Scott Meyers [Meyers2]から読むこずができたす。 むンタヌフェむスクラスは、プロトコルクラスずも呌ばれたす。


むンタヌフェむスクラスを䜿甚するず、プロゞェクトのさたざたな郚分間の䟝存関係を匱めるこずができ、チヌム開発が簡玠化され、コンパむル/アセンブリ時間が短瞮されたす。 むンタヌフェむスクラスを䜿甚するず、実行時にモゞュヌルを遞択的にロヌドするずきに、柔軟で動的な゜リュヌションを簡単に実装できたす。 むンタヌフェむスクラスをむンタヌフェむスAPIラむブラリSDKずしお䜿甚するず、バむナリ互換性の問題の解決が簡単になりたす。


むンタヌフェむスクラスは非垞に広く䜿甚されおおり、ラむブラリSDKのむンタヌフェむスAPI、プラグむンプラグむンなどのむンタヌフェむスを実装するのに圹立ちたす。 Gang of Four [GoF]パタヌンの倚くは、むンタヌフェむスクラスを䜿甚しお自然に実装されたす。 むンタヌフェむスクラスには、COMむンタヌフェむスが含たれたす。 ただし、残念ながら、むンタヌフェむスクラスに基づいた゜リュヌションを実装する堎合、倚くの堎合、ミスが発生したす。 この問題を明確にしおみたしょう。



1.特別なメンバヌ関数、オブゞェクトの䜜成ず削陀


このセクションでは、むンタヌフェむスクラスに提䟛される゜リュヌションを完党に理解するために知っおおく必芁のあるC ++機胜のいく぀かに぀いお簡単に説明したす。



1.1。 特別なメンバヌ関数


プログラマヌが次のリストデフォルトコンストラクタヌ、コピヌコンストラクタヌ、コピヌ代入挔算子、デストラクタからクラスのメンバヌ関数を定矩しおいない堎合は、コンパむラヌがこれを行うこずができたす。 C ++ 11では、このリストに移動コンストラクタヌず移動割り圓お挔算子が远加されたした。 これらのメンバヌ関数は、特別なメンバヌ関数ず呌ばれたす。 それらは䜿甚される堎合にのみ生成され、各機胜に固有の远加の条件が満たされたす。 この䜿甚が完党に隠されおいる可胜性があるこずに泚意しおくださいたずえば、継承を実装する堎合。 必芁な機胜を生成できない堎合、゚ラヌが生成されたす。 再配眮操䜜を陀き、それらはコピヌ操䜜に眮き換えられたす。コンパむラヌによっお生成されるメンバヌ関数は、パブリックで埋め蟌み可胜です。


特別なメンバヌ関数は継承されたせん。掟生クラスで特別なメンバヌ関数が必芁な堎合、コンパむラは垞にそれを生成しようずしたす。プログラマヌが基本クラスで定矩した察応するメンバヌ関数の存圚はこれに圱響したせん。


プログラマヌは、特別なメンバヌ関数の生成を犁止できたす。C++ 11では、C ++ 98で、察応するメンバヌ関数をprivateずしお宣蚀し、定矩しない堎合、 "=delete"構文を䜿甚する必芁がありたす。 クラス継承では、基本クラスで䜜成された特別なメンバヌ関数の生成の犁止は、すべおの掟生クラスに適甚されたす。


プログラマヌがコンパむラヌによっお生成されたメンバヌ関数に慣れおいる堎合、C ++ 11では、宣蚀をドロップするだけでなく、これを明瀺的に瀺すこずができたす。 これを行うには、宣蚀時に"=default"構文を䜿甚する必芁がありたすが、コヌドは読みやすく、アクセスレベルの制埡に関連する远加機胜が衚瀺されたす。


特別なメンバヌ関数の詳现は[Meyers3]にありたす。



1.2。 オブゞェクトの䜜成ず削陀-基本的な詳现


new/delete挔算子を䜿甚しおオブゞェクトを䜜成および削陀するこずは、䞀般的なツヌむンワン操䜜です。 new呌び出すず、最初にオブゞェクトにメモリが割り圓おられたす。 遞択が成功するず、コンストラクタヌが呌び出されたす。 コンストラクタヌが䟋倖をスロヌするず、割り圓おられたメモリは解攟されたす。 delete挔算子が呌び出されるず、すべおが逆の順序で行われたす。最初にデストラクタが呌び出され、次にメモリが解攟されたす。 デストラクタは䟋倖をスロヌしないでください。


new挔算子を䜿甚しおオブゞェクトの配列を䜜成する堎合、メモリは最初に配列党䜓に割り圓おられたす。 遞択が成功するず、れロから始たる配列の各芁玠に察しおデフォルトのコンストラクタヌが呌び出されたす。 コンストラクタヌが䟋倖をスロヌした堎合、配列の䜜成されたすべおの芁玠に぀いお、コンストラクタヌの呌び出しの逆の順序でデストラクタが呌び出され、割り圓おられたメモリが解攟されたす。 配列を削陀するには、 delete[]挔算子配列のdelete挔算子ず呌ばれるを呌び出す必芁がありたす。配列のすべおの芁玠に぀いお、コンストラクタヌの呌び出しず逆の順序でデストラクタが呌び出され、割り圓おられたメモリが解攟されたす。


泚意 単䞀のオブゞェクトたたは配列が削陀されるかどうかに応じお、 delete挔算子の正しい圢匏を呌び出す必芁がありたす。 このルヌルは厳守する必芁がありたす。そうしないず、未定矩の動䜜が発生する可胜性がありたす。぀たり、メモリリヌク、クラッシュなど、䜕でも起こりたす。 詳现に぀いおは、[Meyers2]を参照しおください。


暙準のメモリ割り圓お関数は、芁求を満たすこずがstd::bad_allocず、 std::bad_alloc型の䟋倖をスロヌしたす。


任意の圢匏のdelete挔算子をNULLポむンタヌに適甚しおも安党です。


䞊蚘の説明では、1぀の説明が必芁です。 いわゆる単玔型組み蟌み型、Cスタむル構造䜓の堎合、コンストラクタヌは呌び出されず、デストラクタはどのような堎合でも䜕もしたせん。 セクション1.6も参照しおください。



1.3。 デストラクタアクセスレベル


delete挔算子がクラスぞのポむンタヌに適甚されるずき、そのクラスのデストラクタはdelete利甚可胜でなければなりたせん。 セクション1.6で説明したこの芏則にはいく぀かの䟋倖がありたす。したがっお、デストラクタを安党たたはクロヌズにするこずにより、プログラマはデストラクタが利甚できない堎合にdelete挔算子の䜿甚を犁止したす。 デストラクタがクラスで定矩されおいない堎合、コンパむラは独自にこれを行い、このデストラクタは開かれたすセクション1.1を参照。



1.4。 1぀のモゞュヌルで䜜成ず削陀


newオペレヌタヌがオブゞェクトを䜜成した堎合、それをdeleteオペレヌタヌの呌び出しは同じモゞュヌル内になければなりたせん。 比Fig的に蚀えば、「あなたがそれを取った堎所に眮いおください」。 この芏則はよく知られおいたす;䟋えば、[Sutter / Alexandrescu]を参照しおください。 この芏則に違反するず、メモリの割り圓おず解攟の機胜の「䞍䞀臎」が発生する可胜性があり、原則ずしお、プログラムが異垞終了したす。



1.5。 ポリモヌフィックな削陀


delete挔算子を䜿甚しおむンスタンスが削陀されるクラスのポリモヌフィックな階局を蚭蚈しおいる堎合、基本クラスに開いおいる仮想デストラクタが必芁です。これにより、 delete挔算子が基本クラスぞのポむンタに適甚されるずきに、オブゞェクトの実際のタむプのデストラクタが呌び出されたす。 この芏則に違反するず、基本クラスのデストラクタヌの呌び出しが発生し、リ゜ヌスリヌクが発生する可胜性がありたす。



1.6。 クラス宣蚀が䞍完党な堎合の削陀


delete挔算子の雑倚さは、特定の問題を匕き起こす可胜性がありたす; void*型のポむンタヌたたは䞍完党なプリ゚ンプティブ宣蚀を持぀クラスぞのポむンタヌに適甚できたす。 この堎合、゚ラヌは発生せず、デストラクタの呌び出しだけがスキップされ、メモリを解攟する関数のみが呌び出されたす。 䟋を考えおみたしょう


 class X; //   X* CreateX(); void Foo() {    X* p = CreateX();    delete p; } 

このコヌドは、完党なXクラス宣蚀がdeleteダむダルピアで利甚できない堎合でもコンパむルされたす。 ただし、コンパむル時にVisual Studio、譊告が発行されたす。


warning C4150: deletion of pointer to incomplete type 'X'; no destructor called


XおよびCreateX()実装がある堎合、コヌドはCreateX()たすCreateX()がnew挔算子によっお䜜成されたオブゞェクトぞのポむンタヌを返す堎合、 Foo()呌び出しFoo()正垞に実行され、デストラクタは呌び出されたせん。 これがリ゜ヌスの流出に぀ながる可胜性があるこずは明らかであるため、譊告に泚意する必芁があるこずを改めお説明したす。


このような状況は決しお倧げさなものではなく、スマヌトポむンタヌや蚘述子クラスなどのクラスを䜿甚するず簡単に発生したす。 Scott Meyersは[Meyers3]でこの問題を扱っおいたす。



2.玔粋に仮想的な関数ず抜象クラス


むンタヌフェむスクラスの抂念は、玔粋な仮想関数や抜象クラスなどのC ++の抂念に基づいおいたす。



2.1。 玔粋な仮想機胜


"=0"構造を䜿甚しお宣蚀された仮想関数は、玔粋仮想ず呌ばれたす。


 class X { // ...    virtual void Foo() = 0; }; 

通垞の仮想関数ずは異なり、玔粋な仮想関数は定矩できたせんデストラクタを陀き、セクション2.3を参照が、掟生クラスの1぀で再定矩する必芁がありたす。


玔粋に仮想関数を定矩できたす。 ゚ンブレムサッタヌは、この機胜のいく぀かの䟿利な䜿甚法を提䟛したす[シャッタヌ]。



2.2。 抜象クラス


抜象クラスは、少なくずも1぀の玔粋な仮想関数を持぀クラスです。 抜象クラスから掟生し、少なくずも1぀の玔粋仮想関数をオヌバヌラむドしないクラスも抜象になりたす。 C ++暙準では、抜象クラスのむンスタンスの䜜成は犁止されおおり、非抜象クラスの掟生物のむンスタンスのみを䜜成できたす。 したがっお、抜象クラスが䜜成され、基本クラスずしお䜿甚されたす。 したがっお、コンストラクタヌが抜象クラスで定矩されおいる堎合、コンストラクタヌを開くこずは意味がありたせん。保護する必芁がありたす。



2.3。 玔粋な仮想デストラクタ


堎合によっおは、玔粋な仮想デストラクタを䜜成するこずをお勧めしたす。 ただし、この゜リュヌションには2぀の機胜がありたす。


  1. 玔粋に仮想的なデストラクタを定矩する必芁がありたす。 通垞、デフォルトの定矩が䜿甚されたす。぀たり、 "=default"構造を䜿甚し"=default" 。掟生クラスデストラクタは、継承チェヌン党䜓に沿っお基本クラスデストラクタを呌び出したす。したがっお、キュヌはルヌト玔粋に仮想デストラクタに到達するこずが保蚌されたす。
  2. プログラマが掟生クラスで玔粋な仮想デストラクタを再定矩しおいない堎合、コンパむラはそれを圌のために行いたすセクション1.1を参照。 したがっお、玔粋に仮想的なデストラクタを持぀抜象クラスから掟生したクラスは、デストラクタを明瀺的に再定矩しなくおも抜象性を倱う可胜性がありたす。

玔粋な仮想デストラクタの䜿甚䟋は、セクション4.4にありたす。



3.むンタヌフェむスクラス


むンタヌフェむスクラスは、デヌタを持たない抜象クラスであり、䞻に玔粋な仮想関数で構成されおいたす。 このようなクラスは、デストラクタなどの通垞の仮想関数玔粋に仮想ではないを持぀こずができたす。 ファクトリヌ関数などの静的メンバヌ関数もありたす。



3.1。 実装


むンタヌフェむスクラスの実装は、玔粋に仮想関数が再定矩される掟生クラスになりたす。 同じむンタヌフェむスクラスの実装は耇数存圚する可胜性があり、2぀のスキヌムが可胜です。耇数の異なるクラスが同じむンタヌフェむスクラスを継承する堎合は氎平、むンタヌフェむスクラスがポリモヌフィック階局のルヌトである堎合は垂盎です。 もちろん、ハむブリッドもありたす。


むンタヌフェむスクラスの抂念のキヌポむントは、むンタヌフェむスを実装から完党に分離するこずです。クラむアントはむンタヌフェむスクラスでのみ動䜜し、実装は利甚できたせん。



3.2。 オブゞェクト䜜成


実装クラスにアクセスできないず、オブゞェクトの䜜成時に特定の問題が発生したす。 クラむアントは、実装クラスのむンスタンスを䜜成し、オブゞェクトぞのアクセスに䜿甚するむンタヌフェむスクラスぞのポむンタヌを取埗する必芁がありたす。 実装クラスが䜿甚できないため、コンストラクタヌを䜿甚できないため、実装偎で定矩されおいるファクトリヌ関数が䜿甚されたす。 この関数は通垞、 new挔算子を䜿甚しおオブゞェクトを䜜成し、䜜成されたオブゞェクトぞのポむンタヌを返し、むンタヌフェむスクラスぞのポむンタヌにキャストしたす。 ファクトリヌ関数は、むンタヌフェむスクラスの静的メンバヌにするこずができたすが、これは必ずしも必芁ではありたせん。たずえば、特別なファクトリヌクラスそれ自䜓がむンタヌフェむスクラスになるこずもありたすたたはフリヌ関数のメンバヌにするこずができたす。 ファクトリ関数は、むンタヌフェむスクラスぞの生のポむンタではなく、むンテリゞェントなポむンタを返すこずができたす。 このオプションに぀いおは、セクション3.3.4および4.3.2で説明したす。



3.3。 オブゞェクトを削陀


オブゞェクトの削陀は非垞に重芁な操䜜です。 ゚ラヌが発生するず、メモリリヌクたたは二重削陀が発生し、通垞はプログラムがクラッシュしたす。 以䞋では、この問題を可胜な限り詳现に怜蚎し、誀った顧客行動の防止に倚くの泚意を払っおいたす。


4぀の䞻なオプションがありたす。


  1. delete挔算子を䜿甚したす。
  2. 特別な仮想関数を䜿甚したす。
  3. 倖郚関数を䜿甚したす。
  4. スマヌトポむンタヌを䜿甚した自動削陀。


3.3.1。 delete挔算子を䜿甚delete


これを行うには、むンタヌフェむスクラスに開いおいる仮想デストラクタが必芁です。 この堎合、クラむアント偎のむンタヌフェむスクラスぞのポむンタを呌び出すdelete挔算子は、実装クラスのデストラクタぞの呌び出しを提䟛したす。 このオプションは機胜する堎合がありたすが、成功したず認識するのは困難です。 new呌び出しを取埗し、「障壁」の異なる偎で挔算子をdeleteしたす。実装偎でnew 、クラむアント偎でdeleteしたす。 たた、むンタヌフェむスクラスの実装が別のモゞュヌルで行われた堎合これは非垞に䞀般的なこずです、セクション1.4のルヌル違反が発生したす。



3.3.2。 特別な仮想関数を䜿甚する


別のオプションずしお、より進歩的な方法がありたす。むンタヌフェむスクラスには、オブゞェクトを削陀する特別な仮想関数が必芁です。 そのような関数は、最終的にdelete thisを呌び出すこずになりたすが、これは既に実装偎で行われおいたす。 このような関数は、たずえばDelete()などのさたざたな方法で呌び出すこずができたすが、他のオプションも䜿甚されたす Release() 、 Destroy() 、 Dispose() 、 Free() 、 Close()など。 セクション1.4の芏則に埓うこずに加えお、このオプションにはいく぀かの远加の利点がありたす。


  1. 実装クラスにナヌザヌ定矩のメモリ割り圓お/割り圓お解陀関数を䜿甚できたす。
  2. たずえば、参照カりンタヌを䜿甚しお、実装オブゞェクトの有効期間を制埡するためのより耇雑なスキヌムを実装できたす。

この実斜圢態では、 delete挔算子を䜿甚しおオブゞェクトを削陀しようずする詊みはコンパむルされ、実行されるこずもあるが、これぱラヌである。 むンタヌフェむスクラスでそれを防ぐには、空たたは玔粋に仮想的に保護されたデストラクタがあれば十分ですセクション1.3を参照。 delete挔算子の䜿甚は非垞にマスクできるこずに泚意しおください。たずえば、暙準のスマヌトポむンタヌはdelete挔算子を䜿甚しおデフォルトでオブゞェクトを削陀し、察応するコヌドは実装に深く埋もれおいたす。 保護されたデストラクタを䜿甚するず、コンパむル段階でそのようなすべおの詊行を怜出できたす。



3.3.3。 倖郚関数を䜿甚する


このオプションは、オブゞェクトを䜜成および削陀する手順の特定の察称性を匕き付ける可胜性がありたすが、実際には以前のバヌゞョンよりも利点はありたせんが、倚くの远加の問題がありたす。 このオプションの䜿甚は掚奚されおおらず、これ以䞊考慮するこずはありたせん。



3.3.4。 スマヌトポむンタヌを䜿甚した自動削陀


この堎合、ファクトリ関数はむンタヌフェむスクラスぞの生のポむンタではなく、察応するスマヌトポむンタを返したす。 このスマヌトポむンタヌは実装偎で䜜成され、削陀オブゞェクトをカプセル化したす。削陀オブゞェクトは、スマヌトポむンタヌたたはその最埌のコピヌがクラむアント偎で範囲倖になるず、実装オブゞェクトを自動的に削陀したす。 この堎合、実装オブゞェクトを削陀するための特別な仮想関数は必芁ないかもしれたせんが、保護されたデストラクタが䟝然ずしお必芁であり、 delete挔算子の誀った䜿甚を防ぐ必芁がありたす。 確かに、このような゚ラヌの可胜性は著しく枛少しおいるこずに泚意すべきです。このオプションに぀いおは、セクション4.3.2で詳しく説明したす。



3.4。 実装クラスのむンスタンスのラむフタむムを管理するその他のオプション


堎合によっおは、クラむアントはむンタヌフェむスクラスぞのポむンタを受け取りたすが、それを所有したせん。 実装オブゞェクトのラむフタむムの管理は、実装偎で完党に行われたす。 たずえば、オブゞェクトは静的なシングルトンオブゞェクトにするこずができたすこの゜リュヌションは工堎で䞀般的です。 別の䟋は双方向の盞互䜜甚に関連しおいたす。セクション3.7を参照しおください。 クラむアントはそのようなオブゞェクトを削陀すべきではありたせんが、そのようなむンタヌフェヌスクラスの保護されたデストラクタが必芁です。 delete挔算子の誀った䜿甚を防ぐ必芁がありたす。



3.5。 セマンティクスのコピヌ


むンタヌフェむスクラスの堎合、コピヌコンストラクタヌを䜿甚しお実装オブゞェクトのコピヌを䜜成するこずはできないため、コピヌが必芁な堎合、クラスには実装オブゞェクトのコピヌを䜜成し、むンタヌフェむスクラスぞのポむンタヌを返す仮想関数が必芁です。 このような関数はしばしば仮想コンストラクタヌず呌ばれ、その䌝統的な名前はClone()たたはDuplicate()です。


コピヌ割り圓お挔算子の䜿甚は犁止されおいたせんが、良いアむデアずは芋なされたせん。 コピヌ割り圓お挔算子は垞にペアになりたす;コピヌコンストラクタヌずペアにする必芁がありたす。 デフォルトのコンパむラによっお生成された挔算子は無意味であり、䜕もしたせん。 理論的には、玔粋に仮想の代入挔算子を宣蚀し、その埌にオヌバヌラむドできたすが、仮想代入は掚奚されたせん;詳现は[Meyers1]にありたす。 さらに、割り圓おは非垞に䞍自然に芋えたす。通垞、実装クラスのオブゞェクトぞのアクセスは、むンタヌフェむスクラスぞのポむンタを介しお行われるため、割り圓おは次のようになりたす。


 * = *; 

割り圓お挔算子は最も犁止されおおり、必芁に応じお、そのようなセマンティクスはむンタヌフェむスクラスに察応する仮想関数を持ちたす。


割り圓おを犁止するには2぀の方法がありたす。


  1. 割り圓お挔算子を削陀するこずを宣蚀したす =delete 。 むンタヌフェむスクラスが階局を圢成する堎合、これは基本クラスで十分です。 このメ゜ッドの欠点は、実装クラスに圱響するこずです。犁止も適甚されたす。
  2. デフォルトの定矩 =default で保護された割り圓おステヌトメントを宣蚀し=default 。 これは実装クラスには圱響したせんが、むンタヌフェむスクラスの階局の堎合は、各クラスでそのようなアナりンスを行う必芁がありたす。


3.6。 むンタヌフェむスクラスコンストラクタヌ


倚くの堎合、むンタヌフェむスクラスコンストラクタヌは宣蚀されおいたせん。 この堎合、コンパむラヌは、継承の実装に必芁なデフォルトのコンストラクタヌを生成したすセクション1.1を参照。 このコンストラクタヌは開いおいたすが、安党で十分です。 むンタヌフェむスクラスで、コピヌコンストラクタヌが削陀枈み =delete ずしお宣蚀されおいる堎合、コンパむラヌによるコンストラクタヌの生成はデフォルトで抑制されたす。そのようなコンストラクタヌは明瀺的に宣蚀する必芁がありたす。 デフォルトの定矩 =default で保護するのが自然=default 。 原則ずしお、このような保護されたコンストラクタヌの宣蚀は垞に実行できたす。 䟋はセクション4.4にありたす。



3.7。 双方向の盞互䜜甚


むンタヌフェむスクラスは、双方向通信を䜿甚するのに䟿利です。 むンタヌフェむスクラスを介しおモゞュヌルにアクセスできる堎合、クラむアントはむンタヌフェむスクラスの実装を䜜成し、モゞュヌルでそれらにポむンタヌを枡すこずもできたす。 これらのポむンタヌを介しお、モゞュヌルはクラむアントからサヌビスを受信し、デヌタたたは通知をクラむアントに送信するこずもできたす。



3.8。 スマヌトポむンタヌ


実装クラスのオブゞェクトぞのアクセスは通垞、ポむンタヌを介しお行われるため、スマヌトポむンタヌを䜿甚しおその寿呜を制埡するのは自然なこずです。 ただし、オブゞェクトを削陀するための2番目のオプションを䜿甚する堎合は、暙準のスマヌトポむンタヌを䜿甚しお、ナヌザヌ削陀機胜タむプたたはこのタむプのむンスタンスを転送する必芁があるこずに泚意しおください。 これが行われない堎合、スマヌトポむンタヌはdelete挔算子を䜿甚しおオブゞェクトを削陀し、コヌドは単玔にコンパむルされたせん保護されたデストラクタのおかげ。 暙準のスマヌトポむンタヌカスタムリムヌバヌの䜿甚を含むは、[Josuttis]、[Meyers3]で詳现に説明されおいたす。 カスタムリムヌバヌの䜿甚䟋は、セクション4.3.1にありたす。


, , , .



3.9. -


- const. , , -, .



3.10. COM-


COM- , , COM — , COM- , C, , . COM- C++ , COM.



3.11.


(API) (SDK). . -, -, . , (Windows DLL), : -. . , , . LoadLibrary() , -, .



4.



4.1。


, .


 class IBase { protected:    virtual ~IBase() = default; //   public:    virtual void Delete() = 0; //      IBase& operator=(const IBase&) = delete; //   }; 

.


 class IActivatable : public IBase { protected:    ~IActivatable() = default; //   public:    virtual void Activate(bool activate) = 0;    static IActivatable* CreateInstance(); // - }; 

, , . , IBase . , (. 1.3). , .



4.2.


 class Activator : private IActivatable { // ... private:    Activator(); protected:    ~Activator(); public:    void Delete() override;    void Activate(bool activate) override;    friend IActivatable* IActivatable::CreateInstance(); }; Activator::Activator() {/* ... */} Activator::~Activator() {/* ... */} void Activator::Delete() { delete this; } void Activator::Activate(bool activate) {/* ... */} IActivatable* IActivatable::CreateInstance() {    return static_cast<IActivatable*>(new Activator()); } 

, , , - , .



4.3.



4.3.1.


. - ( IBase ):


 struct BaseDeleter {    void operator()(IBase* p) const { p->Delete(); } }; 

std::unique_ptr<> - :


 template <class I> // I —  IBase using UniquePtr = std::unique_ptr<I, BaseDeleter>; 

, , - , UniquePtr .


-:


 template <class I> // I —  - CreateInstance() UniquePtr<I> CreateInstance() {    return UniquePtr<I>(I::CreateInstance()); } 

:


 template <class I> // I —  IBase UniquePtr<I> ToPtr(I* p) {    return UniquePtr<I>(p); } 

std::shared_ptr<> std::unique_ptr<> , , std::shared_ptr<> . Activator .


 auto un1 = CreateInstance<IActivatable>(); un1->Activate(true); auto un2 = ToPtr(IActivatable::CreateInstance()); un2->Activate(true); std::shared_ptr<IActivatable> sh = CreateInstance<IActivatable>(); sh->Activate(true); 

( — -):


 std::shared_ptr<IActivatable> sh2(IActivatable::CreateInstance()); 

std::make_shared<>() , ( ).


: , . : , - . 4.4.



4.3.2.


. -. std::shared_ptr<> , , ( ). std::shared_ptr<> ( ) - , delete . std::shared_ptr<> - ( ) - . .


 #include <memory> class IActivatable; using ActPtr = std::shared_ptr<IActivatable>; //   class IActivatable { protected:    virtual ~IActivatable() = default; //      IActivatable& operator=(const IActivatable&) = default; //   public:    virtual void Activate(bool activate) = 0;    static ActPtr CreateInstance(); // - }; //   class Activator : public IActivatable { // ... public:    Activator();  //      ~Activator(); //      void Activate(bool activate) override; }; Activator::Activator() {/* ... */} Activator::~Activator() {/* ... */} void Activator::Activate(bool activate) {/* ... */} ActPtr IActivatable::CreateInstance() {    return ActPtr(new Activator()); } 

- std::make_shared<>() :


 ActPtr IActivatable::CreateInstance() {    return std::make_shared<Activator>(); } 

std::unique_ptr<> , , - , .



4.4.


C# Java C++ «», . . IBase .


 class IBase { protected:    IBase() = default;    virtual ~IBase() = 0; // ,       virtual void Delete(); //   public:    IBase(const IBase&) = delete;            //      IBase& operator=(const IBase&) = delete; //      struct Deleter        // -    {        void operator()(IBase* p) const { p->Delete(); }    };    friend struct IBase::Deleter; }; 

, Delete() , .


 IBase::~IBase() = default; void IBase::Delete() { delete this; } 

IBase . Delete() , . - IBase . Delete() , - . Delete() , . , 4.3.1.



5. ,



5.1


, , , , .


, , IException Exception .


 class IException {    friend class Exception;    virtual IException* Clone() const = 0;    virtual void Delete() = 0; protected:    virtual ~IException() = default; public:    virtual const char* What() const = 0;    virtual int Code() const = 0;    IException& operator=(const IException&) = delete; }; class Exception {    IException* const m_Ptr; public:    Exception(const char* what, int code);    Exception(const Exception& src) : m_Ptr(src.m_Ptr->Clone()) {}    ~Exception() { m_Ptr->Delete(); }    const IException* Ptr() const { return m_Ptr; } }; 

Exception , IException . , throw , . Exception , . - , .


Exception , , .


IException :


 class ExcImpl : IException {    friend class Exception;    const std::string m_What;    const int m_Code;    ExcImpl(const char* what, int code);    ExcImpl(const ExcImpl&) = default;    IException* Clone() const override;    void Delete() override; protected:    ~ExcImpl() = default; public:    const char* What() const override;    int Code() const override; }; ExcImpl::ExcImpl(const char* what, int code)    : m_What(what), m_Code(code) {} IException* ExcImpl::Clone() const { return new ExcImpl(*this); } void ExcImpl::Delete() { delete this; } const char* ExcImpl::What() const { return m_What.c_str(); } int ExcImpl::Code() const { return m_Code; } 

Exception :


 Exception::Exception(const char* what, int code)    : m_Ptr(new ExcImpl(what, code)) {} 

, — .NET — , — , C++/CLI. , , , C++/CLI.



5.2


- :


 template <typename T> class ICollect { protected:    virtual ~ICollect() = default; public:    virtual ICollect<T>* Clone() const = 0;    virtual void Delete() = 0;    virtual bool IsEmpty() const = 0;    virtual int GetCount() const = 0;    virtual T& GetItem(int ind) = 0;    virtual const T& GetItem(int ind) const = 0;    ICollect<T>& operator=(const ICollect<T>&) = delete; }; 

, -, .


 template <typename T> class ICollect; template <typename T> class Iterator; template <typename T> class Contain {    typedef ICollect<T> CollType;    CollType* m_Coll; public:    typedef T value_type;    Contain(CollType* coll);    ~Contain(); //     Contain(const Contain& src);    Contain& operator=(const Contain& src); //     Contain(Contain&& src);    Contain& operator=(Contain&& src);    bool mpty() const;    int size() const;    T& operator[](int ind);    const T& operator[](int ind) const;    Iterator<T> begin();    Iterator<T> end(); }; 

. , . , , , , - begin() end() , . (. [Josuttis]), for . . , , .



6. -


. -, . . , ++. , .NET, Java Pyton. . , , . .NET Framework C++/CLI C++. .



7.


-, .


.


  1. delete .
  2. .
  3. .

.


, delete . , .


- , . , , delete .


.


, , , , .





[GoF]
., ., ., . - . .: . 英語から — .: , 2001.


[Josuttis]
, . C++: , 2- .: . 英語から -M。LLC "I.D. », 2014.


[Dewhurst]
, . C++. .: . 英語から — .: , 2012.


[Meyers1]
, . C++. 35 .: . 英語から — .: , 2000.


[Meyers2]
, . C++. 55 .: . 英語から — .: , 2014.


[Meyers3]
, . C++: 42 C++11 C++14.: . 英語から -M。LLC "I.D. », 2016.


[Sutter]
, . C++.: . 英語から — : «.. », 2015.


[Sutter/Alexandrescu]
, . , . ++.: . 英語から -M。LLC "I.D. », 2015.






Source: https://habr.com/ru/post/J427281/


All Articles