c++里面有一个用户自定义的类型转换重载符号,可以将自定义的类转换成其他类型,其语法如下:
class B;
class A
{
public:
operator B();
}
上面只是一个简单的声明,然而这个声明是比较奇怪的,一般函数声明都需要有返回值的类型,这个没有,而实际上它又会返回一个类型是B的实例,所以这个语法稍微有点奇怪,一般也不是很常见,但是感觉还是蛮有用的。
实际上上面的声明,和在B的声明里增加一个由A构造的构造函数是一样的,如下:
class B
{
public:
B(const A&);
}
这两段代码可以起到相同的作用,即隐式转换,如果一个函数的接口需要B,但是提供的是A,那么自动调用构造函数或类型转换重载符隐式地把A转换为B。
来看一个例子:
#include <iostream>
#include <ostream>
// forward declaration
class A;
class B;
// definition of A
class A
{
public:
A(int x) : x_(x) {}
operator B(); // implement this method out of class, as B is im-complete type now
friend std::ostream &operator<<(std::ostream &out, const A &a)
{
out << "Class A at " << &a << ": ";
out << a.x_;
return out;
}
int x_{0};
};
// definition of B
class B
{
public:
B(int x) : x_(x) {}
operator A() { return A(x_); }
friend std::ostream &operator<<(std::ostream &out, const B &b)
{
out << "Class b at " << &b << ": ";
out << b.x_;
return out;
}
int x_{0};
};
A::operator B()
{
return B(x_);
}
int simple_add(const A &a, const B &b)
{
return a.x_ + b.x_;
}
int main()
{
A a(1);
B b(2);
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << simple_add(a, b) << std::endl;
// the following will call type conversion operator automatically
std::cout << simple_add(b, a) << std::endl;
return 0;
}
上面这个例子定义了两个类型A和B,同时两个类型可以相互转换,就如同float和double两种类型可以互相转换一样,simple_add
这个函数的两次调用都会成功的。
那既然已经有了构造函数式的类型转换,这种符号重载式地类型转换又有什么用呢?从功能上来说两者没有区别,从语法上来说,如果要把A转换为B,使用构造函数式转换,那么转换函数是写在B里的,如果B是外部的类,比如stl提供的vector,那么你是没有办法去增加一个构造函数的,这种场景下就只能用符号重载式地隐式转换了。
最后有个问题,如果同时提供了符号重载的隐式转换和构造函数的隐式转换,会优先哪个呢?这个借用cpp reference的一个例子:
struct To {
To() = default;
To(const struct From&) {} // converting constructor
};
struct From {
operator To() const {return To();} // conversion function
};
int main()
{
From f;
To t1(f); // direct-initialization: calls the constructor
// (note, if converting constructor is not available, implicit copy constructor
// will be selected, and conversion function will be called to prepare its argument)
To t2 = f; // copy-initialization: ambiguous
// (note, if conversion function is from a non-const type, e.g.
// From::operator To();, it will be selected instead of the ctor in this case)
To t3 = static_cast<To>(f); // direct-initialization: calls the constructor
const To& r = f; // reference-initialization: ambiguous
}
编译器有个复杂的dispatch机制,来决定用哪个,大家可以试试!