クラスは構造関数と構造関数を持っていなくてもいいですか?

4173 ワード

C++が提供するデフォルト関数
まず、コンパイラがデフォルトのメンバー関数を追加するC++の空のクラスについて説明します.
  • デフォルトコンストラクタおよびコピーコンストラクタ
  • 解析関数
  • 賦値関数(賦値演算子)
  • 値関数
  • プログラムがメンバーを定義していない場合でも、コンパイラは上記の関数を挿入します.つまり、ユーザーがコンストラクション関数とコンストラクション関数を定義していない場合、コンパイラはデフォルトのコンストラクション関数とコンストラクション関数を自動的に追加します.しかし、場合によっては、メンバーの特殊性のため、構造関数と構造関数の作成を自分で行う必要があります.
    コンストラクタベース
    1.コンストラクション関数、コピーコンストラクション関数、賦値関数C++では一般的にオブジェクトを作成し、コピーまたは賦値の方式にはコンストラクション関数、コピーコンストラクション関数、賦値関数の3つの方法がある.
  • コンストラクション関数は、クラスのオブジェクトを作成すると、クラスのデータメンバーを初期化および割り当てするために呼び出される特殊なクラスメンバー関数です.デフォルトのコンストラクション関数にはパラメータがなく、何もしません.非パラメトリックコンストラクション関数が再ロードされていない場合、A aは、デフォルトのコンストラクション関数によってオブジェクト
  • を作成する.
  • コピーコンストラクション関数はC++独自であり、同じクラスに基づくオブジェクトで別のオブジェクトを構築して初期化する特殊なコンストラクション関数です.コピーコンストラクタがリロードされていない場合、デフォルトのコピーコンストラクタによってオブジェクトA a; A b(a); A b=a;がコピーコンストラクタで作成され、オブジェクトbが作成されます.ここでbオブジェクトは存在しないので、aオブジェクトでbを構築し、初期化します.
  • あるクラスのオブジェクトがそのクラスの別のオブジェクトに値を割り当てると、そのクラスの値付け関数が使用されます.賦値関数(賦値演算子)が再ロードされていない場合、デフォルトの賦値関数によって賦値操作A a; A b; b=a;が行われる(ここでa,bオブジェクトは既に存在し、aオブジェクトによってbに賦値されていることを強調する!)

  • 一言で三つのことを覚えています.オブジェクトは存在せず、他のオブジェクトで初期化されていません.構造関数を呼び出しました.オブジェクトが存在せず、別のオブジェクトで初期化されるのがコピーコンストラクション関数です(上記の3つの場合!)オブジェクトが存在し、別のオブジェクトで値を付与するのが、値付与関数です.
    2.深いコピーと浅いコピーについて
  • 浅いコピー:コピーされたオブジェクトの中で1つの外部コンテンツ(たとえばスタックに割り当てられたデータ)が参照されている場合、このオブジェクトをコピーするときに、新旧の2つのオブジェクトを同じ外部コンテンツに指向させるのが浅いコピーです.(ポインタはコピーされているが、指す空間の内容はコピーされていないが、2つのオブジェクトが共通しており、2つのオブジェクトが独立せず、削除空間が存在する)
  • .
  • 深いコピー:このオブジェクトをコピーするときに新しいオブジェクトのために外部オブジェクトの独立したコピーを作成した場合、深いコピーです.

  • 注意:コンストラクション関数はリロードできます.複数、パラメータを持つことができます.構造関数は1つしかなく、パラメータなしで再ロードできません.
    オブジェクト破棄プロセス
    一.構造関数の呼び出し
  • オブジェクトを破棄する最初のステップは、構造関数を呼び出し、次のタスクを完了する.解析関数体コード2を実行する.クラスタイプのメンバーの構造関数を逆順序で呼び出し、すべてのメンバーのサブオブジェクトを解析します.各ベースクラスの構造関数を逆順序で呼び出し、すべてのベースクラスサブオブジェクト
  • を解析する.
    注意:構造関数ボリュームコードの実行は、構造解析プロセス全体の最初のステップであり、構造関数ボリュームコードに依存するすべてのリソースと前提条件が保証され、このコードが実行され、破棄されず、構造解析前の状態が維持されます.
    二.メモリ容量の解放
    オブジェクトを破棄する第2のステップはfreeのようなメカニズムで、メンバーのサブオブジェクト、ベースクラスのサブオブジェクトなどを含め、オブジェクト全体のメモリ空間を解放することです.現在のほとんどのC++コンパイラの実装によると、オブジェクトを破棄するプロセスとオブジェクトを作成するプロセスは、通常は厳密に逆です.
  • 作成:メモリの割当て->ベースクラスの構築->メンバーの構築->コードベースクラスの実行:継承順、左から右、メンバーの構築:宣言順、上から下、
  • の順に構築
  • 破棄:プロファイルコードの実行->プロファイルメンバー->プロファイルベースクラス->メモリベースクラスの解放:継承順、右から左、順次メンバーのプロファイル:宣言順、下から上、順次
  • をプロファイルする
    自分でコンストラクタを書く必要がある場合
    クラスにポインタ変数が含まれている場合は、構造関数を自分で書く必要があります.デフォルトのコンストラクション関数だけを使用することはできません.デフォルトのコピーコンストラクタとデフォルトの割り当て関数は、深いコピーではなく浅いコピーで実現されるためです.コピーコンストラクション関数は、オブジェクトが作成されたときに呼び出され、付与関数はすでに存在するオブジェクトによってのみ呼び出されます.
    String a(“hello”);
    String b(“world”);
    String c = a; //          ,     c(a);
    c = b; //         
    

    コピーコンストラクション関数と付与関数をプロアクティブに作成しない場合、コンパイラはデフォルトの関数を「浅いコピー」で自動的に生成します.クラスにポインタ変数が含まれている場合、この2つのデフォルトの関数にはエラーが隠されています.クラスStringの2つのオブジェクトa,bを例にとると、a. m_ dataのコンテンツはhelloであり、b.m _dataのコンテンツはworldであると仮定する.ここで、aはbに割り当てられ、デフォルトの付与関数の「浅いコピー」はb .m _data = a. m_ dataを実行することを意味する.これは3つのエラーをもたらします.1つはb. m_ data元のメモリが解放されず、メモリが漏洩したことです.2つ目は、b. m_ dataa. m_ dataが同じメモリを指し、aまたはbのいずれかの一方の変動が他方に影響を与えることである.3つ目は、オブジェクトが析出されたとき、m_ dataが2回解放されたことである.
    システムが提供するデフォルトのコピーコンストラクタは、メモリコピー、すなわち浅いコピーで動作するためです.オブジェクトに手動で解放する必要があるオブジェクトが使用されている場合、問題が発生します.この場合、コピーコンストラクタを手動で再ロードし、深いコピーを実行します.
    String::String(const String& other)   //        
    {  
      cout<

    次に、深いコピーと浅いコピーについて説明します.
    解析関数を自分で書く必要がある場合
    クラスにmallocまたはnewで動的に割り当てられたリソースがある場合は、構造関数を書き換える必要があります.
    構造関数の場合:機能はリソースの解放に限らず、クラスの設計者として最後にオブジェクトを使用した後に実行したいアクションを実行できます.オブジェクトを破棄するときに自動的に呼び出されます.たとえば、オブジェクトが存在する役割ドメインの終了カッコやdeleteオペレータなど、構造関数の呼び出しを実現できます.
    オブジェクトがライフサイクルの最終時点で動的に割り当てられたリソースを持たず、後続の作業もできない場合は、構造関数を定義しなくても構いません.
    •クラスに構造関数が定義されていない場合、コンパイラは次のようなデフォルトの構造関数を提供します.
  • 基本タイプのメンバー変数に対して、何もしない
  • クラスタイプのメンバー変数とベースクラスサブオブジェクトに対して、対応するタイプの構造関数
  • を呼び出す.
    これは、デフォルトの解析関数がコンパイラによって提供されるためです.これは、メンバーサブオブジェクト、ベースクラスサブオブジェクトなど、コンパイラからリソースを解放するだけです.コンパイラに表示されないリソース、例えばmallocまたはnewで動的に割り当てられたリソースの場合、デフォルトの解析関数は解放の責任を負いません.自分で定義した解析関数で解放する必要があります.そうしないと、メモリ漏洩が発生します.