クラスEmpty {}を隠すもの

これは、作成しなかった場合でも、C ++が自動的に作成するメソッドに関するメモです。



このメモは誰のためのものですか? 初心者のC ++プログラマにとって興味深いものになることを願っています。 そして、経験豊富なプログラマーは、知識を再び更新して体系化します。





だからあなたが書いた場合



 クラス空{}; 


その後、実際にこのクラスのようなものを作成したことを知ってください。



 クラスEmpty {
公開:
   //パラメータなしのコンストラクタ
  空();
   //コンストラクタをコピーします
  空(const empty&);
   //デストラクタ
   〜空();
   //代入演算子
  空の&演算子=(const empty&);
   //住所を受け取るオペレーター
  空の*演算子&();
   //定数オブジェクトのアドレスを取得する演算子
   const空*演算子&()const;
 }; 


これらの関数は常に作成され、予期しない結果につながる可能性があることに注意してください。



これはどのようにトラブルにつながる可能性がありますか?



最も不愉快なことは、プログラムが動作するときですが、あなたが望むようには動作しません。 この場合、言語に関するエラーは発生しません。 暗黙的に生成されたメソッドは、このような問題を正確に引き起こします。



例1:コンストラクター



オブジェクトの作成/削除に関するメッセージを表示し、静的オブジェクトカウンターをサポートするクラスを検討します(簡単にするために、パブリックintの形式で)。



 クラスCC {
公開:
   CC();
   〜CC();
   static int cnt;
 }; 


実装は簡単です。



  int CC :: cnt(0);
 CC :: CC(){cnt ++;  cout << "create \ n";}
 CC ::〜CC(){cnt--;  cout << "破棄\ n";} 


そのようなプログラムは何をしますか?



  void f(CC o){}
 int main(){
   CC o;
   cout << "cnt =" << o.cnt << "\ n";
   f(o);
   cout << "cnt =" << o.cnt << "\ n";
   f(o);
   cout << "cnt =" << o.cnt << "\ n";
   0を返します。
 } 


結果は、準備ができていない読者を驚かせる可能性があります。



 作成する
  cnt = 1
破壊する
  cnt = 0
破壊する
  cnt = -1
破壊する 


オブジェクトは1回だけ作成され、削除されたという感覚が得られます(3回)。 オブジェクトカウンターはマイナスになります。 同時に、プログラムは静かに実行され、どこでもクラッシュしません。



ご存知のように、これは、コピーのみを行い、何も印刷せず、カウンターを修正しない、自動的に作成されたコピーコンストラクターを考慮しなかったために起こりました。



コピーコンストラクタを自分で追加すれば、これを修正できます



  CC :: CC(定数CC&){
   cnt ++;  cout << "作成(コピー)\ n";
 } 


これで、絶対に妥当な結果が得られます。



 作成する
  cnt = 1
作成(コピー)
破壊する
  cnt = 1
作成(コピー)
破壊する
  cnt = 1
破壊する 


割り当て時に同様の待ち伏せが発生します(演算子=)。 しかし...



例2:住所の取得



...アドレスを取得する非自明な方法を実装した場合、おそらく、おそらく、絶妙な汚いトリックが発生する可能性があります



  CC *演算子&(); 


しかし、彼らは同じ(または他の?)非自明な特性を持っている彼の二重を実現するのを忘れました:



  const CC *演算子&()const; 


これまでのところ、プログラムは非定数オブジェクトに制限されています。



  SS o;
 CC * p;
 p =&o; 


すべてが機能します。 これは非常に長い間続く可能性があり、誰もがCCオブジェクトの配置方法を忘れてしまい、それがクレジットされ、エラーが発生したときにそれについて考えません。



しかし、遅かれ早かれコードが表示されます。



  CC const o;
 CC const * q =&o; 


そして方法



  CC *演算子&(); 


それは裏切りでは機能しません( ここで constのオーバーロードについて既に書いています )。



しかし、おそらく十分な例です。 それらすべての意味はほぼ同じです。 説明されているすべてのトラブルを回避する方法。



これらの誤解から身を守るのはとても簡単です!



最も簡単な方法は、実装を作成せずに、自動的に作成されるすべてのメソッドのプロトタイプを作成することです。



その後、プログラムは単にリンクせず、完全に合理的なメッセージを受け取ります。 私はこれを得ました:



  /var/tmp//ccGQszLd.o(.text+0x314):関数「main」内:
 : `CC :: operator&()const 'への未定義の参照 


あなたのコンパイラはそれを少し異なるように置くかもしれません。



この方法が不器用に思える場合(あらゆる理由があり、私も同意します)、「完全な」方法を作成できますが、それらを非公開にします。



また、コンパイル段階でエラーメッセージを受け取ります。



  count2.cpp:関数 'int main()'内:
 count2.cpp:22:エラー: 'const CC * CC :: operator&()const' is private
 count2.cpp:37:エラー:このコンテキスト内 


このメッセージが何らかの形で見えることに同意します...まともです。



さて、3番目の方法(リストの最後の方法ですが、値による最後の方法ではありません)は、この問題を暗闇に入れずにすべての必要なメソッドを正直に実装することです:-)



All Articles