C++ の明示的なキーワードは、パラメーターが 1 つだけあるクラス コンストラクターを変更する場合にのみ使用できます。その機能は、コンストラクターが暗黙的ではなく明示的であることを示すことです。これに対応する別のキーワードは暗黙的です。つまり、クラス コンストラクターは隠蔽され、宣言されます。デフォルトでは暗黙的に。
それでは、明示的に宣言されたコンストラクターと暗黙的に宣言されたコンストラクターの違いは何でしょうか?次の例を見てみましょう。
class CxString // 没有使用explicit关键字的类声明, 即默认为隐式声明
{
public:
char *_pstr;
int _size;
CxString(int size)
{
_size = size; // string的预设大小
_pstr = malloc(size + 1); // 分配string的内存
memset(_pstr, 0, size + 1);
}
CxString(const char *p)
{
int size = strlen(p);
_pstr = malloc(size + 1); // 分配string的内存
strcpy(_pstr, p); // 复制字符串
_size = strlen(_pstr);
}
// 析构函数这里不讨论, 省略...
};
// 下面是调用:
CxString string1(24); // 这样是OK的, 为CxString预分配24字节的大小的内存
CxString string2 = 10; // 这样是OK的, 为CxString预分配10字节的大小的内存
CxString string3; // 这样是不行的, 因为没有默认构造函数, 错误为: “CxString”: 没有合适的默认构造函数可用
CxString string4("aaaa"); // 这样是OK的
CxString string5 = "bbb"; // 这样也是OK的, 调用的是CxString(const char *p)
CxString string6 = 'c'; // 这样也是OK的, 其实调用的是CxString(int size), 且size等于'c'的ascii码
string1 = 2; // 这样也是OK的, 为CxString预分配2字节的大小的内存
string2 = 3; // 这样也是OK的, 为CxString预分配3字节的大小的内存
string3 = string1; // 这样也是OK的, 至少编译是没问题的, free释放_pstr内存指针的时候可能会报错, 完整的代码必须重载运算符"=", 并在其中处理内存释放
上記のコードでは、なぜ「CxString string2 = 10;」という文が可能なのでしょうか?
C++ では、コンストラクターのパラメーターが 1 つだけの場合、コンパイル時にデフォルトの変換操作が行われます。つまり、コンストラクターのデータ型に対応するデータをこのクラスのオブジェクトに変換します。つまり、コード「CxString string2 = 10;」では、コンパイラは整数を CxString クラス オブジェクトに自動的に変換します。これは実際には次の操作と同等です。
CxString string2(10);
// 或如下代码
CxString temp(10);
CxString string2 = temp;
ただし、上記のコードの _size は文字列メモリ割り当てのサイズを表すため、呼び出しの 2 番目の文「CxString string2 = 10;」と 6 番目の文「CxString string6 = 'c';」は平凡に見えますが、簡単です。戸惑う。この使用を防ぐ方法はありますか? 答えは、明示的なキーワードを使用することです。上記のコードを次のように変更してみましょう。
class CxString // 使用关键字explicit的类声明, 显示转换
{
public:
char *_pstr;
int _size;
explicit CxString(int size)
{
_size = size;
// 代码同上, 省略...
}
CxString(const char *p)
{
// 代码同上, 省略...
}
};
// 下面是调用:
CxString string1(24); // 这样是OK的
CxString string2 = 10; // 这样是不行的, 因为explicit关键字取消了隐式转换
CxString string3; // 这样是不行的, 因为没有默认构造函数
CxString string4("aaaa"); // 这样是OK的
CxString string5 = "bbb"; // 这样也是OK的, 调用的是CxString(const char *p)
CxString string6 = 'c'; // 这样是不行的, 其实调用的是CxString(int size), 且size等于'c'的ascii码, 但explicit关键字取消了隐式转换
string1 = 2; // 这样也是不行的, 因为取消了隐式转换
string2 = 3; // 这样也是不行的, 因为取消了隐式转换
string3 = string1; // 这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载
明示的なキーワードの役割は、クラス コンストラクターの暗黙的な自動変換を防ぐことです。
前述したように、explicit キーワードはパラメーターが 1 つあるクラス コンストラクターに対してのみ有効です。クラス コンストラクターのパラメーターが 2 以上の場合、暗黙的な変換は行われないため、explicit キーワードは無効です。例えば:
class CxString // explicit关键字在类构造函数参数大于或等于两个时无效
{
public:
char *_pstr;
int _age;
int _size;
explicit CxString(int age, int size)
{
_age = age;
_size = size;
// 代码同上, 省略...
}
CxString(const char *p)
{
// 代码同上, 省略...
}
};
// 这个时候有没有explicit关键字都是一样的
ただし、例外があり、最初のパラメータを除くすべてのパラメータがデフォルト値を持つ場合でも、明示的なキーワードは引き続き有効です。このとき、コンストラクタを呼び出すときに渡されるパラメータは 1 つだけであり、これは 1 つのパラメータのみに相当します。この例のクラス コンストラクターは次のとおりです。
class CxString // 使用关键字explicit声明
{
public:
int _age;
int _size;
explicit CxString(int age, int size = 0)
{
_age = age;
_size = size;
// 代码同上, 省略...
}
CxString(const char *p)
{
// 代码同上, 省略...
}
};
// 下面是调用:
CxString string1(24); // 这样是OK的
CxString string2 = 10; // 这样是不行的, 因为explicit关键字取消了隐式转换
CxString string3; // 这样是不行的, 因为没有默认构造函数
string1 = 2; // 这样也是不行的, 因为取消了隐式转换
string2 = 3; // 这样也是不行的, 因为取消了隐式转换
string3 = string1; // 这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载
概要:
明示的なキーワードは、クラス内の単一引数コンストラクターの前でのみ使用する必要があります。引数なしのコンストラクターと複数引数のコンストラクターは常に明示的に呼び出されるため、この場合、コンストラクターの前に明示的に追加することは無意味です。
Google の C++ 仕様では、明示的な利点は、時期尚早な型変換を回避できることであり、欠点はないと述べています。したがって、Google は、すべての単一パラメータのコンストラクタを表示する必要があることに同意します。他のクラスの透過的なラッパーであるクラスなど、コピー コンストラクタを明示的に宣言できないケースはごくわずかです。
効果的な C++ は次のように述べています: 明示的として宣言されたコンストラクターは、通常、明示的でない兄弟よりも人気があります。これらは、コンパイラーが意図しない (そして多くの場合意図しない) 型変換を実行することを禁止するためです。コンストラクターを暗黙的な型変換に使用できるようにする正当な理由がない限り、それを明示的に宣言し、全員が同じポリシーに従うことを奨励します。