以下是一些使用和不使用转换函数的随机情况。
首先,请注意转换函数永远不会用于转换为相同的类类型或基类类型。
参数传递期间的转换
参数传递期间的转换将使用复制初始化的规则。这些规则只考虑任何转换函数,不管是否转换为引用。
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
参数传递只是复制初始化的一种上下文。另一种是使用复制初始化语法的“纯”形式
B b = A(); // called!
转换为参考
在条件运算符中,如果转换为左值的类型,则可以转换为引用类型。
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
另一种到引用的转换是当您直接绑定引用时
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
转换为函数指针
您可能有一个到函数指针或引用的转换函数,并且当进行调用时,它可能会被使用。
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
这个东西有时实际上会变得非常有用。
转换为非类类型
随时随地发生的隐式转换也可以使用用户定义的转换。您可以定义一个返回布尔值的转换函数
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(在这种情况下,转换为 bool 可以通过safe-bool 习惯用法变得更安全,以禁止转换为其他整数类型。)在内置运算符需要某种类型的任何地方都会触发转换。不过,转换可能会妨碍您。
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
调用可能不明确,因为对于成员,第二个参数需要转换,而对于内置运算符,第一个参数需要用户定义的转换。其他两个参数分别完美匹配。在某些情况下,调用可以是明确的(ptrdiff_t
需要与int
那时不同)。
转换函数模板
模板允许一些不错的东西,但最好对它们非常谨慎。以下使类型可转换为任何指针类型(成员指针不被视为“指针类型”)。
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();