explicit关键字的作用就是防止有一个参数的类构造函数进行隐式自动转换。
所以explicit只能用于修饰只有一个参数的类构造函数,表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式)。
explicit关键字只对有一个参数的类构造函数有效, 如果类构造函数参数大于或等于两个时, 是不会产生隐式转换的, 所以explicit关键字也就无效了。
在C++中,构造函数可以允许隐式类型转换,允许单参数构造函数将其参数类型自动转换为其类类型的对象,除非使用explicit关键字显式地禁止。
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);
正确:直接调用单参数构造函数CxString(int size),为CxString对象预分配24字节大小的内存。
CxString string4("aaaa");
正确:直接调用CxString(const char* p)构造函数,使用C字符串"aaaa"初始化对象。
CxString string2 = 10;
正确:利用隐式类型转换,将整数10转换为CxString类型,等价于CxString string2(10);。
CxString string5 = "bbb";
正确:通过隐式类型转换,将C字符串"bbb"转换为CxString对象,实质上调用CxString(const char* p)构造函数。
CxString string6 = 'c';
正确:通过隐式类型转换,将字符'c'(其ASCII码值)作为整数传递给CxString(int size)构造函数。
string1 = 2;
正确: 将整数2隐式转换为CxString类型,然后使用赋值操作。这里假设已重载赋值运算符,以处理CxString对象的赋值。
在C++中, 如果的构造函数只有一个参数时, 那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象。"CxString string2 = 10;"这段代码, 编译器自动将整型转换为CxString类对象, 实际上等同于下面的操作:
CxString string2(10);
或
CxString temp(10);
CxString string2 = temp;
"CxString string2 = 10;" 和"CxString string6 = 'c';" 显得不伦不类, 而且容易让人疑惑。可以在单个参数的构造函数前面使用explicit关键字,阻止这种隐式转换。
class CxString {
public:
char *_pstr;
int _size;
explicit CxString(int size) {
_size = size; // 字符串的预设大小
_pstr = static_cast(malloc(size + 1)); // 分配字符串的内存
memset(_pstr, 0, size + 1);
}
explicit CxString(const char *p) {
int size = strlen(p);
_pstr = static_cast(malloc(size + 1)); // 分配字符串的内存
strcpy(_pstr, p); // 复制字符串
_size = strlen(_pstr);
}
// 析构函数
~CxString() {
free(_pstr); // 释放分配的内存
}
// 拷贝构造函数
CxString(const CxString& other) : _size(other._size) {
_pstr = static_cast(malloc(_size + 1));
strcpy(_pstr, other._pstr);
}
// 赋值运算符
CxString& operator=(const CxString& other) {
if (this != &other) { // 防止自我赋值
char* newpstr = static_cast(malloc(other._size + 1));
strcpy(newpstr, other._pstr);
free(_pstr);
_pstr = newpstr;
_size = other._size;
}
return *this;
}
};
调用结果:
CxString string1(24); // OK
CxString string4("aaaa"); // OK
CxString string2 = 10; // 不行, explicit关键字取消了隐式转换
CxString string6 = 'c'; // 不行, 调用的是CxString(int size), 且size等于'c'的ascii码, explicit关键字取消了隐式转换
CxString string3; // 不行, 因为没有默认构造函数
string1 = 2; // 不行, 因为取消了隐式转换
string2 = 3; // 不行, 因为取消了隐式转换
string3 = string1; // 不行, 因为取消了隐式转换, 除非类实现操作符"="的重载
Effective C++:除非有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit,鼓励大家遵循相同的政策。