【问题标题】:Overloading operator + in c++ to add two arrays [duplicate]在c ++中重载运算符+以添加两个数组[重复]
【发布时间】:2020-12-13 11:23:52
【问题描述】:

任务是重载运算符 + 以便添加两个数组。 Array 是一个有两个私有成员 int* data 和 int m(array of array) 的类。

void Array::setM(int m){
this->m = m;
this->data = new int[this->m];
}

int& Array::operator[](int i){
return this->data[i];
}


Array& Array::operator+(Array& a){
Array res;
if (this->m >= a.m) {
    res.setM(this->m);
    for (int i=0; i<this->m; i++){
    res.data[i] = this->data[i] + a.data[i];
    }
}
else if (this->m < a.m) {
    res.setM(a.m);
    for (int i=0; i<a.m; i++){
    res.data[i] = this->data[i] + a.data[i];
    }
}
Array& rez = res;
return rez;
}

这是主要的:

int main()
{
Array a(3);
Array& a1 = a;
a1[0] = 1;
a1[1] = 2;
a1[2] = 4;

Array b(3);
Array& b1 = b;
b1[0] = 1;
b1[1] = 2;
b1[2] = 4;

Array& c = a1.operator+(b1);
for (int i=0; i<3; i++){
    cout<<c[i]<<" ";
}
return 0;
}

当返回类型为 Array 时,该函数工作正常,但当返回类型为 Array& 时,它返回 173104 4200736 4200896。我从 c++ 开始,所以引用让我有点困惑,我没有看到返回引用的函数点输入?

【问题讨论】:

  • operator+ 不应返回引用。只需返回一份。
  • 关于运算符重载的更多智慧:What are the basic rules and idioms for operator overloading?
  • 带有引用的 kicker 是被引用的变量必须比引用的需要更长。
  • @cigien 你的意思是像这样的 Array operator+(Array& a)?
  • 是的,没错,但参数应该是 const 以及函数本身。甚至是免费功能Array operator+(Array const &amp;, Array const &amp;)。请参阅显示的链接@user4581301。

标签: c++ class reference operator-overloading


【解决方案1】:

让我们逐步考虑您的运算符实现。

对于初学者来说,右手操作数不会在运算符中更改。所以函数应该至少声明为

Array& operator+( const Array& a );

该函数在其主体中创建了一个Array 类型的新对象。

Array res;

因此,由于对象是函数的局部变量,因此您可能不会返回对它的引用。这意味着运算符应该声明为

Array operator+( const Array& a );

const Array operator+( const Array& a );

这段代码sn-p

if (this->m >= a.m) {
    res.setM(this->m);
    for (int i=0; i<this->m; i++){
    res.data[i] = this->data[i] + a.data[i];
    }
}

a.m 小于this-&gt;m 时可以调用未定义的行为。

由于成员函数不改变左操作数,所以该函数应该是一个常量成员函数。

const Array operator +( const Array& a ) const;

通常此类运算符被声明为类的单独友元函数。

friend const Array operator+( const Array &a, const Array &b );

考虑到您在运算符中使用的算法,可以通过以下方式定义它(在类定义之外。或者如果您想在类定义中定义它,那么您需要使用说明符friend)

const Array operator+( const Array &a, const Array &b )
{
    int m = std::min( a.m, b.m );
    Array res( m );

    for ( int i = 0; i < m; i++ )
    {
        res.data[i] = a.data[i] + b.data[i];
    }

    return res;
}

注意函数setM会产生内存泄漏,因为它不会删除Array类型的对象的早期分配内存

void Array::setM(int m){
this->m = m;
this->data = new int[this->m];
}

也就是说这个函数是不安全的。

还要记住,带参数的构造函数应该用函数说明符explicit 声明。否则,您可能会遇到整数到 Array 类型的意外转换。

当您动态分配数组时,您至少需要显式编写析构函数、复制构造函数和复制赋值运算符。

【讨论】:

    【解决方案2】:

    你在这里违反了规则,你得到了所谓的未定义行为。您的程序可能会因分段错误而崩溃,或者它可能会输出垃圾,就像您观察到的那样。

    你看,你正在返回一个对局部变量的引用。这是不好的。让我解释一下。

    您在函数中声明的变量通常具有自动存储功能。这意味着它们具有明确定义的存在开始(声明)和存在结束,即其范围的结束。在您的情况下,这是函数的结尾:

    Array& Array::operator+(Array& a) {
        Array res;
        if (this->m >= a.m) {
            res.setM(this->m);
    
            for (int i=0; i<this->m; i++){
                res.data[i] = this->data[i] + a.data[i];
            }
        } else if (this->m < a.m) {
            res.setM(a.m);
    
            for (int i = 0; i < a.m; i++) {
                res.data[i] = this->data[i] + a.data[i];
            } // <-- here, `i` dies.
        }
    
        Array& rez = res;
        return rez;
    } // <-- here, `res` dies.
    

    所以引用rez 指向一个死变量。阅读它被标准归类为未定义的行为。

    显而易见的解决方案是按值返回,并且您还应该对参数进行 const 引用:

     Array Array::operator+(Array const& a) {
        Array res;
        
        // [...]
    
        return res;
    }
    

    在这种情况下,编译器将复制(或移动)res 对象。请记住,编译器非常擅长他们的工作,并且很可能在这种特殊情况下应用复制省略。这意味着不会有副本,变量res将直接在返回通道中构造。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-13
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-14
      相关资源
      最近更新 更多