网站首页 > 技术文章 正文
技术背景
在C++中,当一个构造函数只有一个必要参数时,它会被视为一个隐式转换函数,能够将参数类型转换为类类型。这种隐式转换在某些情况下是方便的,但也可能会导致意外的行为和难以调试的错误。为了避免这些问题,C++引入了explicit关键字。
实现步骤
1. 未使用explicit关键字的情况
#include <iostream>
struct Foo {
// 单参数构造函数,可用于隐式转换
Foo(int x) {}
};
struct Faz {
// 同样是转换构造函数
Faz(Foo foo) {}
};
// 参数类型为Foo
void bar(Foo foo) {}
int main() {
// 转换构造函数允许传递int
bar(42);
// 也允许这样的初始化
Foo foo = 42;
// 错误!这需要两次转换(int -> Foo -> Faz)
// Faz faz = 42;
return 0;
}
在上述代码中,Foo的构造函数允许将int类型隐式转换为Foo类型,因此bar(42)和Foo foo = 42;都是合法的。
2. 使用explicit关键字的情况
#include <iostream>
struct Foo {
// 显式构造函数,防止隐式转换
explicit Foo(int x) {}
};
struct Faz {
// 同样是转换构造函数
Faz(Foo foo) {}
};
// 参数类型为Foo
void bar(Foo foo) {}
int main() {
// 错误!不允许隐式转换
// bar(42);
// 错误!不允许隐式转换
// Foo foo = 42;
// 显式调用构造函数
bar(Foo(42));
Foo foo(42);
return 0;
}
在这个例子中,Foo的构造函数被声明为explicit,这意味着编译器不能再使用该构造函数进行隐式转换。因此,bar(42)和Foo foo = 42;会导致编译错误,必须显式地调用构造函数。
3. explicit用于转换函数
#include <iostream>
struct X {
explicit X(int a); // X可以从int显式构造
explicit operator bool() const; // X可以显式转换为bool
};
void foo(bool b) { }
int main() {
X x(0);
// 错误!X不能隐式转换为bool
// foo(x);
// 显式转换
foo(static_cast<bool>(x));
return 0;
}
在C++11及以后的版本中,explicit关键字也可以用于转换函数,防止隐式转换。
核心代码
#include <iostream>
// 未使用explicit关键字
class String1 {
public:
String1(int n); // 分配n字节给String对象
String1(const char *p); // 用char *p初始化对象
};
String1::String1(int n) {
std::cout << "String1(int n) called" << std::endl;
}
String1::String1(const char *p) {
std::cout << "String1(const char *p) called" << std::endl;
}
// 使用explicit关键字
class String2 {
public:
explicit String2(int n); // 分配n字节
String2(const char *p); // 用字符串p初始化对象
};
String2::String2(int n) {
std::cout << "String2(int n) called" << std::endl;
}
String2::String2(const char *p) {
std::cout << "String2(const char *p) called" << std::endl;
}
int main() {
// 未使用explicit,允许隐式转换
String1 s1 = 'x';
// 使用explicit,不允许隐式转换,编译错误
// String2 s2 = 'x';
String2 s2(10);
return 0;
}
最佳实践
- 默认使用explicit:对于单参数构造函数,除非有明确的需求,否则应该默认将其声明为explicit,以避免意外的隐式转换。
- 在接口设计中使用explicit:在类的接口中使用explicit关键字可以强制用户明确表达他们想要的转换,提高代码的可读性和可维护性。
常见问题
1. 为什么explicit关键字只能用于单参数构造函数?
严格来说,explicit关键字可以用于多参数构造函数,但只有当构造函数可以用于隐式转换时才有意义。通常,多参数构造函数不会用于隐式转换,因此explicit关键字在这种情况下的使用较少。
2. explicit关键字对默认构造函数有影响吗?
默认构造函数(无参数构造函数)通常不会用于隐式转换,因此explicit关键字对默认构造函数没有实际影响。
3. explicit关键字可以用于复制构造函数吗?
复制构造函数通常用于对象的复制,而不是隐式转换,因此explicit关键字对复制构造函数没有实际影响。
- 上一篇: C++每日一问(3): SFINAE是什么意思
- 下一篇: C++关键字之const
猜你喜欢
- 2025-04-27 详解C++三种new操作符
- 2025-04-27 C++引用的深入一步学习,总结有哪些场景?linux C++第11讲
- 2025-04-27 C++ 中的卷积神经网络 (CNN)
- 2025-04-27 谈谈 C++ 的原子操作与并发
- 2025-04-27 指针的迷宫:C/C++程序员的终极挑战
- 2025-04-27 C++11新特性概述,初始化,auto、for、智能指针、哈希表等
- 2025-04-27 C++启蒙之旅--数据类型怎么玩
- 2025-04-27 最新最全linux c/c++服务器后台开发面试题合集
- 2025-04-27 掌握CONST:C/C++代码安全与优化
- 2025-04-27 C++之父谈关于C++的五个需要被重新认识的观点(上)
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)