explicit

変換コンストラクタのように、暗黙的にコンストラクタが呼ばれる場合が結構あるが、そうしてほしくない場合もあったりする・・・。
explicitを付けることで、暗黙的なコンストラクタ呼び出しを禁止することができる・・・。

まず、基本となるclass_test1を定義する・・・。

int型iを引数に取るコンストラクタを定義・・・。

こんな感じで実装・・・。
class_test1のコンストラクタが呼ばれたことも出力・・・。

class_test2は、

class_test1を継承・・・。
引数付きコンストラクタにexplicitを付けている・・・。

i_がprivateなのでset_iを使ってセット・・・。
ここでも呼ばれたことを出力・・・。

class_test3は、

class_test1を継承・・・。
class_test1の参照を引数に取るコンストラクタ・・・。

obj.get_iで渡されたclass_test1オブジェクトのi_を取得し、そのままset_iでセット・・・。

class_test4は、

class_test2を継承・・・。
class_test2の参照を引数に取るコンストラクタ・・・。
explicitが付いている・・・。

こちらもobj.get_iをそのままset_i・・・。

class_test1は特に制限もなく、引数形式、初期化形式、ともに値を渡すことができる・・・。
class_test2は、intを引数に取るコンストラクタにexplicitが付いているので、暗黙的に変換コンストラクタを呼ぶことができず、初期化形式は使えない・・・。

class_test3はexplicitが付いていないので、初期化形式でclass_test1オブジェクトを渡すことができる・・・。
さらにobj7のようなこともできる・・・。
class_test3にはintを引数に取るコンストラクタはないが、class_test1の参照を引数に取るコンストラクタはあり、変換コンストラクタで30が渡されたclass_test1オブジェクトが暗黙的に生成され、それがclass_test3のコンストラクタに渡されるという現象が起きているのである・・・。
しかし、obj8のように直接的に初期化形式で指定することはできない模様・・・。

class_test4はexplicitが付いているので、初期化形式自体を使うことができない・・・。
また、obj11のような方法は、class_test2のintを引数に取るコンストラクタにexplicitが付いていて、暗黙的な変換が出来ないのでNG・・・。

この中でコンパイルが通るのは、obj1, obj2, obj3, obj5, obj6, obj7, obj9・・・。

$ g++ -o explicit explicit.cpp test1.cpp test2.cpp test3.cpp test4.cpp
$ ./explicit
class_test1::class_test1(int i)
class_test1::class_test1(int i)
class_test2::class_test2(int i)
class_test3::class_test3(const class_test1 &obj)
class_test3::class_test3(const class_test1 &obj)
class_test1::class_test1(int i)
class_test3::class_test3(const class_test1 &obj)
class_test4::class_test4(const class_test2 &obj)
i_ = 10
i_ = 20
i_ = 30
i_ = 10
i_ = 20
i_ = 30
i_ = 30
$

obj7で、class_test1::class_test1(int i)とclass_test3::class_test3(const class_test1 &obj)の2つが呼ばれている・・・。
暗黙的にclass_test1オブジェクトを生成していたことの証拠である・・・。
しかし、intを引数に取るコンストラクタが無いのに、obj7(30)というのはいささか強引にも見える・・・。
explicitを付ければそういったこともできなくなる・・・。

Sample/cpp/explicit/explicit/src/explicit at master · bg1bgst333/Sample · GitHub