在此代码中,使用了两种方法来允许将Y对象转换为X对象。通过g ++编译总是选择构造函数。如果构造函数是私有的,如:
private : Y(const X&){std::cout << "Y constructor...\n" ; }
运算符或构造函数可以防止转换。如果构造函数是私有的和明确的
private : explicit Y(const X&){std::cout << "Y constructor...\n" ; }
编译器使用运算符。这是通过使转换构造函数为私有来阻止自动转换的常用方法,以及编译器用于进行此类转换的规则。
#include <iostream>
class Y ;
class X {
public:
operator Y()const ;
};
class Y {
public:
Y(){}
private :
explicit Y(const X&){std::cout << "Y constructor...\n" ; }
};
X::operator Y() const { std:: cout << "Operator Y...\n" ;
return Y ();
}
void func(Y Y_object) {}
int main() {
X X_object ;
Y Y_object ;
func(X_object) ;
Y_object = X_object ;
}
答案 0 :(得分:2)
转换函数和转换构造函数指定从转换函数/构造函数所针对的类型到参数中所采用类型的转换。换句话说,您正在从X
转换为Y
而不是正如您所说的那样。
当存在从X
到Y
的转换时,编译器会考虑通过函数重载决策实现最佳转换。由于在重载解析期间不考虑访问控制,因此如果私有转换是更可行的转换,则可以选择私有转换而不是公共转换。如果它们同样可行,那么两次转换之间也可能存在歧义。
调用函数func(X_object)
需要从X
到Y
进行隐式转换。考虑X::operator Y() const
和转换构造函数explicit Y::Y(const X&)
,选择转换运算符是因为构造函数标记为explicit
,因此只能通过直接初始化语法或显式转换来调用。
func(Y(X_object));
func(static_cast<Y>(X_object));
这两个都调用显式转换构造函数,因为构造函数和参数的参数类型完全匹配。
使用复制分配将X
隐式转换为Y
时,会出现同样的情况。隐式转换运算符是一个比显式构造函数更可行的函数:
Y_object = X_object; // calls X_object.operator Y()
如果使用直接初始化语法或显式强制转换,转换构造函数将是最可行的函数。
为防止从X
到Y
的隐式转换,最好为Y
提供显式构造函数而不是显式转换运算符。在这种情况下,似乎没有理由将构造函数设置为私有,除非您想要一起阻止转换,但如果您想这样做,那么只需将构造函数保持为未声明。
答案 1 :(得分:0)
防止隐式类型转换的最常用方法是不要声明转换运算符并创建构造函数explicit
。但是,如果您想保留转换运算符,也可以使用explicit
关键字明确表示:
class X {
public:
explicit operator Y() const;
};