我在继承重载+运算符时遇到问题。 让我举个例子。
class Data{
protected:
int data[3];
public:
Data(){
data[0] = data[1] = data[2] = 0;
}
Data operator+(const Data& other)
{
Data temp = *this;
for(int i=0;i<3;i++){
temp.data[i] += other.data[i]
}
return temp;
}
};
class DataInterited:public Data{
public:
};
/******************Main*****************/
DataInterited d1,d2,d3;
d3 = d1 + d2; //=> This is compile error
此代码生成编译错误,
'operator ='不匹配(操作数类型为'DataInterited'和'Data')
我认为我必须为operator+
实施DataInherited
,以便它返回DataInherited
个实例。 但是通过这种方式,我无法避免代码重复。
有没有办法让d3=d1+d2;
行正确,同时避免重复+ operator
实现?
答案 0 :(得分:1)
您需要了解一些事项。
首先,始终将operator+
实现为operator+=
方面的自由函数。它可以节省代码重复并且效率最高。
其次,DataInherited
中没有构造函数可以使用Data
作为参数。这很重要,因为Data::operator+
的结果是数据,而不是DataInherited
。
更正后的代码:
#include <iostream>
#include <algorithm>
class Data{
protected:
int data[3];
public:
Data(){
data[0] = data[1] = data[2] = 0;
}
Data(const Data& other)
{
std::copy(std::begin(other.data), std::end(other.data), data);
}
Data& operator=(const Data& other)
{
std::copy(std::begin(other.data), std::end(other.data), data);
return *this;
}
Data& operator+=(const Data& other)
{
for(int i=0;i<3;i++){
data[i] += other.data[i];
}
return *this;
}
};
Data operator+(Data left, const Data& right)
{
return left += right;
}
class DataInterited:public Data{
public:
DataInterited(Data d = {})
: Data(std::move(d))
{}
};
using namespace std;
auto main() -> int
{
DataInterited d1,d2,d3;
d3 = d1 + d2; //=> This is no longer a compile error
return 0;
}
答案 1 :(得分:-1)
Koenig运营商转发到increment_by
功能。
派生类如果需要不同的行为,可以实现自己的increment_by
重载。
跳过SFINAE的东西,所以不好的类型会给出错误的错误。
class Data{
public:
template<class D, class Rhs>
friend D operator+=(D&& lhs, Rhs&& rhs){
increment_by(lhs,std::forward<Rhs>(rhs));
return std::forward<D>(lhs);
}
template<class Lhs, class Rhs>
friend Lhs operator+(Lhs lhs, Rhs&& rhs){
lhs+=std::forward<Rhs>(rhs);
return std::move(lhs);
}
friend void increment_by(Data& self, Data const&other){
for(int i=0;i<6;i++){
self.data[i] += other.data[i];
}
}
};
+
和+=
都是模板朋友,因此传递的类型可以是派生类。因此输入不会丢失,
increment_by
需要重写。如果没有,请不要管它。
不要不必要地离开这个类型。从base转换为derived基本上抛出派生类型的点。