2017年10月21日
《その87》 コンストラクタ初期化子
クラス型オブジェクトの生成過程について
次の ClassA型のクラスは、Sub型のクラスをデータメンバとして持っています。
この ClassA型のクラスオブジェクトが生成される場合について考えてみます。
------------------------------------------------
class Sub {
int a, b;
public:
Sub() {}; // ★1.
Sub(int a, int b);
};
class ClassA {
std::string str;
Sub sub;
public:
ClassA(std::string s, int a, int b) {
str = s;
sub = Sub(a, b); // ★2.
}
};
------------------------------------------------
いま、ClassA型のオブジェクト aaa を作成するものとします。
ClassA aaa("abc", 10, 20);
【1】 メンバ str が "abc" で初期化されるまでの過程
(1) string型の str が生成される。
(2) string型のデフォルトコンストラクタが呼び出されて、データメンバ str が空文字列を
表すように初期化される。
※ 実際は、この (2) で本当の意味の初期化作業は完了し、あとは代入作業になります。
(3) コンストラクタ本体が実行され、仮引数 s に受け取った文字列 "abc" が、データメンバ str
に代入される。
具体的には、"abc" を格納できる大きさの記憶域を、new演算子で確保し直すことになります。
このように、かなりコストの高い手順が踏まれています。
【2】 クラス型メンバ sub が初期化されるまでの過程
(1) Sub型の sub が生成される。
(2) Sub型のデフォルトコンストラクタ(★1.)が呼び出されて、クラス型データメンバ sub が
初期化される。
※ 実際は、この (2) で本当の意味の初期化作業は完了し、あとは代入作業になります。
※ デフォルトコンストラクタ(★1.)がないとエラーになります。
(3) コンストラクタ本体が実行され、初期化済のデータメンバ sub に 10, 20 の値がセットされる。
具体的には、
sub = Sub(a, b);
の箇所で、まず、Sub型の一時オブジェクト Sub(10, 20) が作られ、それが sub に代入される
ことになります。
このように、かなりコストの高い手順が踏まれています。
コンストラクタ初期化子
上に記述した ClassA型のコンストラクタは、次のようなコードでした。
ClassA(std::string s, int a, int b) {
str = s;
sub = Sub(a, b);
}
これには、上述の【1】,【2】に書いたようなコスト的な問題がありました。
次のコードは、このコンストラクタを、コンストラクタ初期化子を用いて書きかえたものです。
ClassA(std::string s, int a, int b)
: str(s), sub(a, b)
{
};
下線の箇所がコンストラクタ初期化子です。全てのデータメンバに対してメンバ初期化子を与えたので、コンストラクタの本体部分が空になっています。
コンストラクタ初期化子を用いることで、
データメンバ string str や Sub sub を、【1】や【2】にある「代入」の手順を経ずに、直接、
初期化することができます。
以上の内容を、簡単なプログラムにまとめてみました。
#include <string>
#include <iostream>
class Sub {
int a, b;
public:
Sub() { a = 1; b = 2; }
Sub(int a, int b) {
this->a = a;
this->b = b;
}
int get_a() { return a; }
int get_b() { return b; }
};
class ClassA {
std::string str;
Sub sub;
public:
ClassA(std::string s, int a, int b)
: str(s), sub(a, b)
{}
int get_a() { return sub.get_a(); }
int get_b() { return sub.get_b(); }
std::string get_str() { return str; }
};
int main() {
ClassA aaa("衆議院議員総選挙", 1000, 2000);
std::cout << aaa.get_a() << '\n';
std::cout << aaa.get_b() << '\n';
std::cout << aaa.get_str() << '\n';
}
--
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/6880357
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック