文章目录
- 1. **防止隐式类型转换**
- 示例1:没有使用`explicit`
- 示例2:使用`explicit`
- 2. **防止拷贝初始化**
- 示例1:没有使用`explicit`
- 示例2:使用`explicit`
- 3. **防止隐式类型转换的链式调用**
- 示例1:没有使用`explicit`
- 示例2:使用`explicit`
- 4. **防止隐式类型转换的歧义**
- 示例1:没有使用`explicit`
- 示例2:使用`explicit`
- 总结
在C++中,
explicit
关键字用于修饰构造函数和转换运算符,其主要目的是防止隐式类型转换和拷贝初始化,从而提高代码的可读性和安全性。以下是
explicit
的详细作用和使用场景:
1. 防止隐式类型转换
当构造函数被声明为explicit
时,它不能用于隐式类型转换。这意味着不能通过单个参数的构造函数隐式地将一个类型转换为另一个类型。
示例1:没有使用explicit
class MyClass {
public:MyClass(int x) : value(x) {} // 非explicit构造函数int value;
};void printMyClass(MyClass obj) {std::cout << obj.value << std::endl;
}int main() {printMyClass(10); // 隐式调用 MyClass(int) 构造函数return 0;
}
在这个例子中,MyClass(int)
构造函数是非explicit
的,因此可以隐式地将int
类型转换为MyClass
类型。调用printMyClass(10)
时,会隐式地调用MyClass(10)
构造函数。
示例2:使用explicit
class MyClass {
public:explicit MyClass(int x) : value(x) {} // explicit构造函数int value;
};void printMyClass(MyClass obj) {std::cout << obj.value << std::endl;
}int main() {// printMyClass(10); // 错误:无法隐式调用 MyClass(int) 构造函数printMyClass(MyClass(10)); // 显式调用 MyClass(10) 构造函数return 0;
}
在这个例子中,MyClass(int)
构造函数被声明为explicit
,因此不能隐式地将int
类型转换为MyClass
类型。调用printMyClass(10)
时,会报错,必须显式地调用MyClass(10)
构造函数。
2. 防止拷贝初始化
explicit
构造函数不能用于拷贝初始化,但可以用于直接初始化。
示例1:没有使用explicit
class MyClass {
public:MyClass(int x) : value(x) {} // 非explicit构造函数int value;
};int main() {MyClass obj = 10; // 拷贝初始化,隐式调用 MyClass(int) 构造函数return 0;
}
在这个例子中,MyClass(int)
构造函数是非explicit
的,因此可以用于拷贝初始化。
示例2:使用explicit
class MyClass {
public:explicit MyClass(int x) : value(x) {} // explicit构造函数int value;
};int main() {// MyClass obj = 10; // 错误:无法隐式调用 MyClass(int) 构造函数MyClass obj(10); // 直接初始化,显式调用 MyClass(int) 构造函数return 0;
}
在这个例子中,MyClass(int)
构造函数被声明为explicit
,因此不能用于拷贝初始化。必须使用直接初始化的方式显式调用构造函数。
3. 防止隐式类型转换的链式调用
explicit
可以防止多个隐式类型转换的链式调用,从而避免潜在的错误。
示例1:没有使用explicit
class MyClass {
public:MyClass(int x) : value(x) {} // 非explicit构造函数int value;
};class YourClass {
public:YourClass(MyClass obj) : myObj(obj) {} // 非explicit构造函数MyClass myObj;
};int main() {YourClass obj = 10; // 隐式调用 MyClass(int) 和 YourClass(MyClass)return 0;
}
在这个例子中,MyClass(int)
和YourClass(MyClass)
构造函数都是非explicit
的,因此可以隐式地将int
类型转换为MyClass
类型,再将MyClass
类型转换为YourClass
类型。
示例2:使用explicit
class MyClass {
public:explicit MyClass(int x) : value(x) {} // explicit构造函数int value;
};class YourClass {
public:explicit YourClass(MyClass obj) : myObj(obj) {} // explicit构造函数MyClass myObj;
};int main() {// YourClass obj = 10; // 错误:无法隐式调用 MyClass(int) 和 YourClass(MyClass)YourClass obj(MyClass(10)); // 显式调用 MyClass(10) 和 YourClass(MyClass)return 0;
}
在这个例子中,MyClass(int)
和YourClass(MyClass)
构造函数都被声明为explicit
,因此不能隐式地进行类型转换。必须显式地调用构造函数。
4. 防止隐式类型转换的歧义
在某些情况下,多个构造函数可能导致隐式类型转换的歧义。使用explicit
可以避免这种歧义。
示例1:没有使用explicit
class MyClass {
public:MyClass(int x) : value(x) {} // 非explicit构造函数MyClass(double x) : value(static_cast<int>(x)) {} // 非explicit构造函数int value;
};void printMyClass(MyClass obj) {std::cout << obj.value << std::endl;
}int main() {printMyClass(10); // 隐式调用 MyClass(int) 构造函数printMyClass(10.5); // 隐式调用 MyClass(double) 构造函数return 0;
}
在这个例子中,MyClass(int)
和MyClass(double)
构造函数都是非explicit
的,因此可以隐式地将int
和double
类型转换为MyClass
类型。
示例2:使用explicit
class MyClass {
public:explicit MyClass(int x) : value(x) {} // explicit构造函数explicit MyClass(double x) : value(static_cast<int>(x)) {} // explicit构造函数int value;
};void printMyClass(MyClass obj) {std::cout << obj.value << std::endl;
}int main() {// printMyClass(10); // 错误:无法隐式调用 MyClass(int) 构造函数// printMyClass(10.5); // 错误:无法隐式调用 MyClass(double) 构造函数printMyClass(MyClass(10)); // 显式调用 MyClass(int) 构造函数printMyClass(MyClass(10.5)); // 显式调用 MyClass(double) 构造函数return 0;
}
在这个例子中,MyClass(int)
和MyClass(double)
构造函数都被声明为explicit
,因此不能隐式地进行类型转换。必须显式地调用构造函数,避免了潜在的歧义。
总结
explicit
关键字的主要作用是防止隐式类型转换和拷贝初始化,从而提高代码的可读性和安全性。在设计类时,如果某个构造函数或转换运算符不应该被隐式调用,应该使用explicit
关键字进行修饰。