我浏览了很多与转换相关的问题,但似乎没有一个是以这种方式讨论显式关键字的。这是代码:
struct B;
struct A{
/*explicit*/ A(const B&){ cout << 1; } // *1
};
struct B{
/*explicit*/ operator A()const{ cout << 2; } // *2
};
void foo(const A &){}
int main(void){
B b;
foo( /*static_cast<A>*/ (b) ); // *3
}
结果:(Y:未注释,N:注释,X:任一)
# | *1 | *2 | *3 |output|
1 | N | N | N |error |
2 | N | N | Y | 1 |
3 | N | Y | N | 1 |
4 | N | Y | Y | 1 |
5 | Y | N | N | 2 |
6 | Y | N | Y | 1 |
7 | Y | Y | N |error |
8 | Y | Y | Y | 1 |
1、7是错误,这是正常的。(不明确且没有自动转换)
2似乎构造函数有更高的优先级,但为什么呢
3、5很容易理解
4很奇怪,因为它不叫显式的。为什么
6可能是由于"显式"或构造函数具有更高的优先级。哪一个是原因?8似乎构造函数有更高的优先级,但为什么呢
有人能解释一下吗?谢谢
一个非常好的问题。
首先,explicit
并不意味着"如果需要显式转换,它就有优先权"。它的意思是"这个东西只能显式调用"。因此,它创建了一些无法调用的情况,而不是在其他情况下强制调用它。
另一件需要考虑的事情是static_cast
是直接初始化,而将参数传递给函数是复制初始化。除其他外,复制初始化从不使用显式构造函数。另一件需要注意的事情是,直接初始化需要使用类的构造函数(显式或非显式)。尽管这并不意味着转换不能执行直接初始化:它可以用于转换构造函数的参数,如果构造函数是编译器生成的副本,那么它看起来就像转换函数执行的直接初始化一样(而事实上它是由副本构造函数执行的)。尝试在不定义复制构造函数的情况下声明它(禁用复制技术),您将看到转换函数不再在直接初始化上下文中工作:它将进行编译,但会导致链接错误。
考虑到这一点:
- 显而易见
- 直接初始化需要构造函数,因此会调用它
- 显而易见
- 和2一样,真的。声明转换函数
explicit
只会防止它被隐式调用,而不会强制在显式上下文中使用 - 显而易见
- 同样,直接初始化需要构造函数,并且允许使用显式构造函数
- 显而易见
- 另一种直接初始化的情况