C++ でコピーコンストラクタを利用する
この記事では、C++ でコピーコンストラクターを利用する方法のいくつかの方法について説明します。
C++ でコピーコンストラクタを使用して同じタイプの別のオブジェクトからオブジェクトを初期化する
このクラスには、まとめてコピー制御
と呼ばれるいくつかの操作があります。これらの操作は、特定のクラスタイプのオブジェクトをコピー、移動、割り当て、または破棄する方法を定義します。この記事では、コピーコンストラクターとコピー代入のみに焦点を当てます。
コピーコンストラクターは、参照として渡された引数の値を複製することによってオブジェクトを初期化します(通常は const
参照として渡されます)。コンパイラーは未定義の操作の合成操作を自動的に定義するため、クラスは他のコピー制御操作のようにコピーコンストラクターを定義する必要はありません。それでも、後者の場合は問題が発生することがよくあります。合成されたコピーコンストラクターは、引数オブジェクトの各メンバーを作成中のオブジェクトにコピーします。他のクラスタイプのメンバーが存在する可能性があり、それらはコピーコンストラクターによってコピーされます。対照的に、組み込み型オブジェクトは直接コピーされます。
次のサンプルコードは、MyClass
のコピーコンストラクターの動作を示しています。これは、コピーコンストラクターの唯一の必須引数を取り、データメンバーを初期化します。一方、コピーコンストラクターには追加の引数を含めることができます。これはオプションであり、デフォルト値である必要があります。
タイプ MyClass
のオブジェクトが最初に作成されると、デフォルトのコンストラクターが呼び出されます。ただし、新しく作成された m3
変数に m1
を割り当てると、コピーコンストラクターが呼び出されます。後者の操作はコピー初期化とも呼ばれ、コピーコンストラクターを利用したり、コンストラクターを移動したりする場合があります(別の記事で説明)。
#include <iostream>
using std::cout;
using std::endl;
using std::pair;
class MyClass {
private:
int n1{};
int n2{};
public:
MyClass(int x, int y) : n1(x), n2(y) {
cout << "Constructor 1 is called" << endl;
};
MyClass(const MyClass& src) {
cout << "Copy Constructor is called " << endl;
n1 = src.n1;
n2 = src.n2;
}
auto getPair() { return pair<int, int>(n1, n2); }
~MyClass() = default;
};
int main() {
MyClass m1(12, 21);
cout << "------------------" << endl;
MyClass m2(11, 33);
cout << "------------------" << endl;
MyClass m3 = m1;
cout << "------------------" << endl;
cout << m1.getPair().first << m1.getPair().second << endl;
cout << m2.getPair().first << m2.getPair().second << endl;
cout << m3.getPair().first << m3.getPair().second << endl;
return EXIT_SUCCESS;
}
出力:
Constructor 1 is called
------------------
Constructor 1 is called
------------------
Copy Constructor is called
------------------
1221
1133
1221
C++ で代入演算子のコピーを使用してオブジェクトの代入演算子のオーバーロードを定義する
コピー代入演算子は、同じタイプのオブジェクトを代入する方法を定義します。ユーザーが明示的に定義しない場合、コンパイラーはこの操作も合成します。コピーの割り当ては、他の演算子のオーバーロード関数と同様に説明されています。クラスと同じ型の引数を取り、通常は左側のオペランドへの参照を返します。コピー代入演算子は、メンバー関数として定義する必要があります。
次のコードスニペットは、MyClass
のコピー代入演算子を追加し、m2
オブジェクトを m1
に割り当てている間にそれを呼び出します。
#include <iostream>
using std::cout;
using std::endl;
using std::pair;
class MyClass {
private:
int n1{};
int n2{};
public:
MyClass(int x, int y) : n1(x), n2(y) {
cout << "Constructor 1 is called" << endl;
};
MyClass(const MyClass& src) {
cout << "Copy Constructor is called " << endl;
n1 = src.n1;
n2 = src.n2;
}
MyClass& operator=(const MyClass& src) {
cout << "Copy Assignment is called " << endl;
n1 = src.n1;
n2 = src.n2;
return *this;
}
auto getPair() { return pair<int, int>(n1, n2); }
~MyClass() = default;
};
int main() {
MyClass m1(12, 21);
cout << "------------------" << endl;
MyClass m2(11, 33);
cout << "------------------" << endl;
MyClass m3 = m1;
cout << "------------------" << endl;
m1 = m2;
cout << "------------------" << endl;
cout << m1.getPair().first << m1.getPair().second << endl;
cout << m2.getPair().first << m2.getPair().second << endl;
cout << m3.getPair().first << m3.getPair().second << endl;
return EXIT_SUCCESS;
}
出力:
Constructor 1 is called
------------------
Constructor 1 is called
------------------
Copy Constructor is called
------------------
Copy Assignment is called
------------------
1221
1133
1221