C++运算符重载的一些小细节

一个通用的运算符重载助记公式

// 对于前置的一元运算符@A:
type Foo::operator@();  // 成员函数
type operator@(Foo& );  // 非成员函数

// 对于后置的一元运算符A@
// 另外这里还要返回自加之前的"旧"值,所以返回一份拷贝
type Foo::operator@(int);          // 成员函数
type operator@(const Foo&, int);   // 非成员函数

// 对于后置的二元运算符A@
type Foo::operator@(const Foo&);          //成员函数
type operator@(const Foo&, const Foo&);    // 非成员函数

哑参数

在后置一元运算符的重载函数声明中,int只起到区分前置后置的作用,没有什么实际效果,称为“哑参数”

操作符重载的返回值

所有的操作符的重载函数的返回值都没有指定,编译器会根据实际的代码来进行上面所声明的运算符的匹配调用,如:

@a => (a).operator@()  // 成员函数的情况
或者 
@a => operator@(a)     // 非成员函数的情况

a@b => (a).operator@(b)  // 成员函数的情况
或者
a@b => operator@(a,b)   // 非成员函数的情况

所以这里的操作符重载的返回值可以根据语义自行设计。考虑设计Matrix的operator*(),我们都知道矩阵和矩阵之间是可以相乘的,例如A = B * C这样的语句,被编译器这样调用:

A = B.operator*(C);

如果operator()的返回类型是Matrix值类型,那么就意味着在operator*()内部的实现中需要进行内存的额外拷贝,但这样的好处是无论做什么样的运算,都不会影响到B的内存值。就像这样:

Matrix Matrix::operator*(const Matrix& another)
{
    Matrix ret;
    // some logic...
    return ret;
}

Matrix A = B.operator*(C);

为了避免函数返回ret的额外开销,这里在实际工程中可以使用C++11的移动语义完成。
当然,为了避免额外的内存拷贝,也可以返回Matrix&类型。但是问题在于,operator*()会创造一个额外的变量A,不额外分配的话A的内存是从哪儿来?当编译器进行如下调用时:

Matrix& Matrix::operator*(const Matrix& another)
{
    // 一些在原地(in place)计算的操作
    this.resouce = this.resouce * another.resouce;

    return *this;
}

Matrix &A = B.operator*(C);

可以发现,这样的操作影响到了B本身。
以上根据矩阵类本身的语义对operator@返回值的设计进行了简单的示例。operator@的返回值并没有明确的规定,所以需要根据需求自己设计。

为什么建议operator=返回Foo&?

待补充…

什么时候operator@返回Foo或者Foo&?

待补充…

posted @ 2020-03-04 12:29  joeyzzz  阅读(284)  评论(0编辑  收藏  举报