C++でexplicitの使い方
C++でESP32開発をしている際に、見慣れない explicit にであったので調べてみました。
explicitの意味: はっきりと述べられた、曖昧さのない、明確な、明白な
だそうです。下記のようなクラスを作っていたところ、BluetoothHelperのコンストラクタ部分で、explicitを付けるようにサジェストされました。
cpp
class BluetoothHelper {
public:
explicit BluetoothHelper(const String& deviceName);
bool on();
void off();
void send(const String& message);
String waitForResponse();
...
};
気になって調べたので、次にまとめます。
explicitの使い方
C++におけるexplicitキーワードは、コンストラクタが暗黙的な型変換から呼び出されることを防ぐために使用されます。コンストラクタが一つの引数を取る場合(または全ての引数にデフォルト値がある場合)、そのコンストラクタは変換コンストラクタとして機能し、コンパイラによって暗黙的にその型への変換を行う場合があります。 つまり、引数がひとつだけのコンストラクタを持つクラスだと、「暗黙的な型変換」という特別な動作をしてしまうことのようです。explicitキーワードをコンストラクタに付けることで、そのコンストラクタを通じた暗黙的な型変換を禁止し、型変換が意図されたものであることを明示的にできます。
explicitがない場合
cpp
class MyClass {
public:
MyClass(int x) { ... } // このコンストラクタは暗黙的な型変換を許可する
};
この場合、MyClassのオブジェクトはint型の値から暗黙的に生成することができます。
cpp
MyClass obj = 10; // intからMyClassへの暗黙的な型変換が行われる
使い方によっては便利そうですが、今回の場合はちょっと意図していない使い方ですね。
explicitがある場合
cpp
class MyClass {
public:
explicit MyClass(int x) { ... } // このコンストラクタは暗黙的な型変換を禁止する
};
この場合、MyClassのオブジェクトをint型の値から生成するには、明示的な型変換が必要になります。つまり先ほどのような「暗黙的な型変換」の書き方はエラーになります。
cpp
MyClass obj = 10; // エラー: 暗黙的な型変換は禁止されている
MyClass obj(10); // OK: 明示的なコンストラクタ呼び出し
MyClass obj = MyClass(10); // OK: 明示的な型変換
これで普段通り、意図した実装になりました。
explicitのメリット
メリット | 説明 |
---|---|
型安全性の向上 | プログラマが意図しない型変換を防ぎ、 バグの可能性を減らします。 |
コードの意図の明確化 | コンストラクタを通じた型変換が 意図的にのみ行われるようにし、 コードの読み手にその意図を明確に伝えます。 |
まとめ
「暗黙的な型変換」は、特に大きなコードベースや複数人での開発プロジェクトにおいて、意図しないバグの原因となることがあります。ですからexplicitキーワードを使用して、バグを未然に防ぎましょう。