C++里的奇怪语法之一——类型转换重载符

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机制,来决定用哪个,大家可以试试!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

boldyoungster

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值