C++におけるコンストラクタ委譲(委任)の基本と使い方
C++11以降では、コンストラクタ委譲(constructor delegation)という便利な機能が利用できます。これは、あるコンストラクタが同じクラスの別のコンストラクタを呼び出す仕組みのことで、初期化処理の重複をなくし、コードを簡潔に保つために役立ちます。
従来のコードの課題
まずは次のプログラムを見て、どのような問題があるのかを確認してみましょう。
例
#include <iostream>
using namespace std;
class MyClass {
int a, b, c;
public:
MyClass(){
a = b = c = 0;
}
MyClass(int c) {
// aとbの初期化は冗長。ここではcの初期化だけで十分
a = 0;
b = 0;
this->c = c;
}
void display(){
cout << "a : " << a << ", b : " << b << ", c : " << c;
}
};
main() {
MyClass my_obj(5);
my_obj.display();
}出力結果
a : 0, b : 0, c : 5
コード自体は正しく動作していますが、よく見ると冗長な部分があります。引数付きのコンストラクタ MyClass(int c) の中で、aとbを0に初期化する処理が、引数なしのコンストラクタと重複しているのです。
仮に引数なしのコンストラクタでaとbを1に設定するように変更した場合、引数付きのコンストラクタ側も修正が必要になり、手間が増えるうえに修正漏れによるバグのリスクも生じます。そこで活躍するのがコンストラクタ委譲です。
コンストラクタ委譲を使った改善例
メンバ初期化リストで : MyClass() のように記述することで、別のコンストラクタへ処理を委譲できます。
例
#include <iostream>
using namespace std;
class MyClass {
int a, b, c;
public:
MyClass(){
a = b = c = 0;
}
MyClass(int c) : MyClass(){ // コンストラクタ委譲を使用
this->c = c;
}
void display(){
cout << "a : " << a << ", b : " << b << ", c : " << c;
}
};
main() {
MyClass my_obj(5);
my_obj.display();
}出力結果
a : 0, b : 0, c : 5
実行結果は先ほどと同じですが、コードの重複が完全になくなりました。MyClass(int c) は、まず MyClass() を呼び出してa・b・cをすべて0で初期化し、その後、自分の処理としてcだけに値を代入します。
コンストラクタ委譲のメリット
- コードの重複を排除できる:共通の初期化処理を1か所にまとめられます。
- 保守性の向上:初期化ロジックを変更する際、修正箇所が1つで済みます。
- バグの防止:複数のコンストラクタ間で初期化内容が食い違うリスクを減らせます。
使用時の注意点
委譲元のコンストラクタ本体は、委譲先のコンストラクタの実行が完了した後に呼び出されます。また、委譲を行う場合、メンバ初期化リストで他のメンバを同時に初期化することはできません(委譲のみが記述可能です)。これらの点に留意すれば、コンストラクタ委譲はC++のコード品質を高める非常に有効な機能です。
-
C++のコピーコンストラクタと代入演算子の違いを徹底解説
C++におけるコピーコンストラクタと代入演算子(コピー代入演算子)は、どちらも「あるオブジェクトを別のオブジェクトで初期化・設定する」ために使用されます。しかし、両者には重要な違いがあります。最大の相違点はメモリの扱いです。コピーコンストラクタは新しいオブジェクトに対して独立したメモリ領域を確保します。一方、代入演算子は新しいメモリ領域を確保せず、既存のオブジェクトに値を上書きする形になります。つまり、すでに存在するメモリブロックに対して操作が行われる点が特徴です。コピーコンストラクタの構文classname (const classname &obj) { // コンストラクタの本体
-
C++のコピーコンストラクタとは?仕組みと実装方法をサンプルコード付きで解説
コピーコンストラクタは、コンストラクタの一種です。同じクラスのオブジェクトを受け取り、その値を使って新しいオブジェクトを生成・初期化します。もしクラス内でコピーコンストラクタが定義されていない場合、コンパイラが自動的にデフォルトのコピーコンストラクタを生成します。ただし、ポインタ変数や動的メモリ確保(new/delete)を持つクラスでは、デフォルトのコピーは浅いコピー(shallow copy)となり、同じメモリ領域を複数のオブジェクトが参照してしまう問題が発生します。そのため、このようなクラスでは独自のコピーコンストラクタを定義することが必須となります。コピーコンストラクタのサンプルプログ