C++のデフォルト関数とdefaultとdeleteの使い方


時間:2014.05.08
場所:基地
--------------------------------------------------------------------------------
一、クラスのデフォルト関数
a.クラスのデフォルトメンバー関数
1.デフォルトのコンストラクタ
2.デフォルトの解析関数
3.コピーコンストラクタ
4.コピー付与関数
5.移動構造関数
6.コピー関数の移動
b.クラスでカスタマイズしたオペレータ関数
1.operator
2.operator&
3.operator&&
4.operator*
5.operator->
6.operator->*
7.operator new
8.operator delete
同時にC++は,プログラマがこれらの関数のカスタムバージョンを実現すると,コンパイラはデフォルトバージョンを自動的に生産しないことを規定している.注意デフォルトバージョンは自動的に生成されません.もちろん、手動でデフォルトバージョンを生成することもできます.パラメータを定義するコンストラクション関数を自分で定義する場合は、パラメータを持たないバージョンを宣言してパラメータなしの変数の初期化を完了すると、コンパイルはデフォルトのパラメータなしバージョンを自動的に提供しません.キーワードdefaultを使用してデフォルトコンストラクション関数の生成を制御し、コンパイラが関数のデフォルトバージョンを生成することを明示的に示すことができます.例:
class MyClass
{
  public:
    MyClass()=default;  //             ,   POD 
    MyClass(int i):data(i){}
  private:
    int data;
};

デフォルト関数の生成を制限したい場合があります.典型的にはコピーコンストラクション関数の使用を禁止し、従来の方法ではコピーコンストラクション関数をprivateと宣言することは実現を提供していないため、コンストラクションオブジェクトをコピーする際にコンパイルが通過できず、C++11はdeleteキーワードを使用してコンパイラが関数のデフォルトバージョンを生成しないことを明示的に示す.例:
class MyClass
{
  public:
     MyClass()=default;
     MyClass(const MyClass& )=delete;
  ......
}

もちろん、関数がdeleteによってオーバーロードされると、その関数を再ロードするのも違法であり、この関数を削除関数と呼ぶことに慣れています.
--------------------------------------------------------------------------------
二、defaultとdeleteのその他の用途
クラスではdefaultとdeleteでメンバー関数を修飾してデフォルト関数または削除関数にすることができます.クラスの外では、クラス定義の外でメンバー関数を修飾することもできます.たとえば、次のようにします.
class MyClass
{
  public:
    MyClass()=default;
    MyClass() &operator=(const MyClass& );
);
//       default         
inline MyClass& MyClass::operator=(const MyClass& )=default;

deleteの明示的な削除については、メンバー関数に限らず、defaultはクラスに作用する一部のメンバー関数に限られていることも知られています.そこでdeleteを使用して、不要な暗黙的なデータ型変換を回避することもできます.例:
class MyClass
{
  public:
    MyClass(int i){};
    MyClsss(char c)=delete;  //  char       
};
void Fun(MyClass m){}
int main()
{
  Func(3);
  Func('a');  //      
  MyClass m1(3);
  MyClass m2('a');  //      
}

これはcharバージョンのコンストラクション関数が削除された後、charからMyClassオブジェクトを構築しようとする方法が許されないためです.しかし、この文の関数を削除すると、コンパイラは暗黙的にaを整数に変換してコンパイルを通過させ、整数構造関数を呼び出します.これはあなたが望んでいるものではないかもしれません.
しかし、もしそうなら:
class MyClass
{
  public:
    MyClass(int i){};
    explicit MyClsss(char c)=delete;  //  explicit char       
};
void Fun(MyClass m){}
int main()
{
  Func(3);
  Func('a');  //     
  MyClass m1(3);
  MyClass m2('a');  //      
}

コンストラクション関数explicitを作成すると、コンストラクション関数のようにcharが発生しません.
コンパイラは、charコンストラクションバージョンが削除されたため、Funcの呼び出し用にcをintに変換しようとします.すなわち、Func(\a')はMyClass(int)コンストラクションを1回呼び出し、コンパイルをスムーズに行います.そこでexplicitとdeleteの混用を提唱しません.通常の関数deleteとタイプの効果もあります.例:
void Func(int i){};
void Func(char c)=delete;  //    char  
int main()
{
  Func(3);
  Func('c);  //      
  return 0;
}

ここではFuncのcharバージョンが削除されているため、Func('c')はコンパイルに失敗します.
deleteの興味深い使い方はoperator newオペレータを削除し、スタックにクラスを割り当てるオブジェクトを符号化することです.
次のようになります.
void* operator new(std::size_t)=delete;

また、構造関数もdeleteできます.これは、メモリの場所を指定してメモリ割り当てを行うときに、オブジェクトレベルのクリーンアップを完了するために構造関数を必要としないことを目的としています.この場合、スタック上または静的な構造のカスタムタイプを制限するために、構造関数の削除を表示できます.