12.3 转换
12.3 转换
1、类对象的类型转换可由构造函数和转换函数指定。这些转换称为用户定义的转换,可用于隐式类型转换(第4章)、初始化(8.5)和显式类型转换(5.4,
2、只有不存在歧义(10.2,
3、[注:有关转换在函数调用中的使用可参见13.3和下面的例子。]
4、最多只能有一个用户定义的转换(构造函数或转换函数)能隐式地应用于单个值。例如:
class X {
// ...
public:
operator int();
};
class Y {
// ...
public:
operator X();
};
Y a;
int b = a; // error:
// a.operator X().operator int() not tried
int c = X(a); // OK: a.operator X().operator int()
5、仅当不存在歧义的时候才能隐式地使用用户定义的转换。派生类中的转换函数并不能隐藏基类的转换函数,除非两个函数转换到相同的类型。函数重载解析(
class X {
public:
// ...
operator int();
};
class Y : public X {
public:
// ...
operator char();
};
void f(Y& a)
{
if (a) { // ill-formed:
// X::operator int() or Y::operator char()
// ...
}
}
12.3.1 通过构造函数的转换
1、没有使用函数说明符explicit声明,且能通过单个参数调用的构造函数定义了一个从构造函数的第一个参数类型到其所属类类型的转换。这样的构造函数称为转换构造函数。例如:
class X {
// ...
public:
X(int);
X(const char*, int =0);
};
void f(X arg)
{
X a = 1; // a = X(1)
X b = "Jessie"; // b = X("Jessie",0)
a = 2; // a = X(2)
f(3); // f(X(3))
}
2、显式构造函数以非显式构造函数同样的方式构造对象,但它仅在有直接初始化成分(8.5)或显式转型(
class Z {
public:
explicit Z();
explicit Z(int);
// ...
};
Z a; // OK: default-initialization performed
Z a1 = 1; // error: no implicit conversion
Z a3 = Z(1); // OK: direct initialization syntax used
Z a2(1); // OK: direct initialization syntax used
Z* p = new Z(1); // OK: direct initialization syntax used
Z a4 = (Z)1; // OK: explicit cast used
Z a5 = static_cast<Z>(1); // OK: explicit cast used
3、非显式拷贝构造函数(12.8)是一种转换构造函数。隐式声明的拷贝构造函数不是显式构造函数;它只能作为隐式类型转换调用。
12.3.2 转换函数
1、名字形式如下的类X成员函数
conversion-function-id:
operator conversion-type-id
conversion-type-id:
type-specifier-seq conversion-declaratoropt
conversion-declarator:
ptr-operator conversion-declaratoropt
定义了一个从X到conversion-type-id所指定类型的转换。这样的函数称为转换函数。类、枚举和类型定义名不能在type-specifier-seq中声明。既不能给转换函数指派参数类型,也不能给转换函数指派返回类型。转换函数(
2、例如:
class X {
// ...
public:
operator int();
};
void f(X a)
{
int i = int(a);
i = (int)a;
i = a;
}
在上述三种情况下,所有的赋值操作都通过X::operator int()转换。
3、用户定义的转换函数并不限于赋值和初始化。例如:
void g(X a, X b)
{
int i = (a) ? 1+a : 0;
int j = (a&&b) ? a+b : i;
if (a) { // ...
}
}
4、conversion-type-id不能表示函数类型,也不能表示数组类型。在conversion-function-id中的conversion-type-id是最长可能的conversion-declarators序列。[注:这可以防止在声明符*和乘法操作符之间产生歧义。例如:
&ac.operator int*i; // syntax error:
// parsed as: &(ac.operator int *) i
// not as: &(ac.operator int)*i
这里的*是指针声明符而不是乘法操作符。]
5、转换函数是可继承的。
6、转换函数可为虚函数。