是否可以通过索引为运算符重载分配用户定义的数组? - C ++

时间:2014-11-21 04:02:44

标签: c++ arrays operator-overloading

<小时/> 问题:当我尝试按索引分配IntArray对象时,我收到以下错误:

  

&#34;表达式不可分配。&#34;

错误由iadrv.cpp中的以下代码行生成:

IntArray a(10);
for(int i = a.low(); i <= a.high(); i++)
    a[i] = i * 10;

我能够将整个IntArray对象分配给另一个,如a = b;,但是当一个特定的索引被引用到&#34时,表达式是不可分配的&#34;发生错误。

编辑:我从大多数功能中移除了const声明,而我没有得到&#34;表达式不可分配&#34;错误了。但是,setName现在给出错误:

  

&#34; ISO C ++ 11不允许从字符串文字转换为&#39; char *&#39;&#34;

此错误是由iadrv.cpp中的以下代码引起的:

a.setName("a");

<小时/> 程序说明:

我编写了一个IntArray类(在C ++中),其中重载了以下运算符:

  • &#34; []&#34; :允许索引范围检查
  • &#34; =&#34; :允许数组赋值
  • &#34; +&#34; :允许将两个数组的总和分配给第三个数组
  • &#34; + =&#34; :允许将两个数组的总和分配给第一个数组
  • &#34;&LT;&LT;&#34; :允许输出数组的内容

该计划还包括以下功能:

  • setName:设置IntArray对象的名称
  • getName:返回IntArray对象的名称
  • low:返回最小的合法索引
  • high:返回最大的合法索引
  • length:返回元素数

驱动程序(iadrv.cpp,iadrv.h)将对IntArray类(IntArray.cpp,IntArray.h)运行测试,以确定是否所有运算符都已正确重载。

注意:对于每个阵列测试数据,驱动程序将简单地乘以 在每个数组初始化或修改后立即将数组索引10并输出其内容。当程序遇到运行时错误时,应该通过适当的诊断模拟&#34;停止而不是实际停止程序。

<小时/> 代码:

IntArray.h

//  IntArray.h

#ifndef __IntArray__IntArray__
#define __IntArray__IntArray__

#include <iostream>
#include <fstream>
#include <iomanip>

using namespace std;

class IntArray {
private:
    int a, b;
    int size;
    int * num;
    char * name;
public:
    IntArray(int start, int finish);
    IntArray(int finish = 10);
    IntArray(const IntArray &); //constructor copy
    ~IntArray();
    int low() const;
    int high() const;
    char * getName() const;
    //removed the const declaration from functions below
    int & operator [] (int);     //made to return int&
    friend ostream & operator << (ostream &, IntArray &);
    void setName(char *);
    int length() const;
    const IntArray & operator = (IntArray &);
    const IntArray & operator + (IntArray &);
    bool operator += (IntArray &);

};

#endif /* defined(__IntArray__IntArray__) */

IntArray.cpp

//  IntArray.cpp

#include "IntArray.h"

#include <iostream>
#include <fstream>

using namespace std;

extern ofstream csis;

IntArray::IntArray(int start, int finish) {
    if (start > finish) {
        cout << "Simulating a halt.";
        a = finish;
        b = start;
    }
    else {
        a = start;
        b = finish;
    }
    size = b-a;
    num = new int[size];
    name = new char[1];
    for (int i = 0; i < size; i++) {
        num[i] = 0;
    }
}
IntArray::IntArray(int finish) {
    size = finish;
    a = 0;
    b = finish - 1;
    num = new int[size];
    name = new char[1];
    for (int i = 0; i < size; i++) {
        num[i] = 0;
    }
}
IntArray::IntArray (const IntArray & right): size(right.size) {
    num = new int[size];
    name = new char[1];
    for (int i = 0; i < size; i++) {
        num[i] = right.num[i];
    }
}
IntArray::~IntArray() {
    delete[] num;
    delete [] name;
}
int IntArray::low() const{
    return a;
}
int IntArray::high() const{
    return b;
}
char * IntArray::getName() const{
    return name;
}
void IntArray::setName(char * n) {
    name = n;
}
//removed const declarations
//made to return int&
int & IntArray::operator [] (int subscript) const{
    if (subscript < a || subscript > b) {
        cout << "subscript: " << subscript << endl;
        cout << "Out of bound error. Simulating a halt." << endl;
        return num[a];
    }
    return num[subscript-a];
}
int IntArray::length() const{
    //b-a = size
    return (b-a);
}
//removed const declarations
ostream & operator << (ostream & output, IntArray & array) {
    for (int i = array.low(); i <= array.high(); i++) {
        output << array.name << "[" << i << "] = " << array[i] << endl;
    }
    return output;
}
//removed const declarations
IntArray & IntArray::operator = (IntArray & right) {
    if (length() == right.length()) {
        for (int i = 0; i <= length(); i++) {
            num[i] = right[right.low()+i];
        }
    return * this;
    }
    else {
        delete [] num;  //reclaim space
        delete [] name;
        size = right.length();
        num = new int [size]; //space created
        cout << "Different sized arrays. Simulating a hault" << endl;
    }
    return * this;
}
//removed const declarations
IntArray & IntArray::operator + (IntArray & right) {
    int * ptr;
    ptr = new int [right.length()];
    if (length() == right.length()) {
        for (int i = 0; i < length(); i++) {
            ptr[i] = num[i] + right[right.low()+i];
        }
    }
    return * this;
}
//removed const declarations
bool IntArray::operator += (IntArray & right) {
    if (length() == right.length()) {
        for (int i = 0; i <= right.length(); i++) {
            num[i] += right[right.low()+i];
        }
        return true;
    }
    cout << "Could not add the sum of the arrays into first array. Simulating a halt." << endl;
    return false;
}

iadrv.h

//  iadrv.h

#ifndef p6_iadrv_h
#define p6_iadrv_h

#include "intarray.h"

int main();
void test1();
void wait();

#endif

iadrv.cpp

//  iadrv.cpp

#include <iostream>
#include <iomanip>
#include <fstream>
#include <stdlib.h>
#include "iadrv.h"

using namespace std;

ofstream csis;

int main() {
    csis.open("csis.dat");
    test1();
    csis.close();
}

void test1() {
    system("clear");
    cout << "1. Array declared with single integer: IntArray a(10);" << endl << endl;
    csis << "1. Array declared with single integer: IntArray a(10);" << endl << endl;
    IntArray a(10);
    for(int i = a.low(); i <= a.high(); i++)
        a[i] = i * 10;
    a.setName("a");
    cout << a << endl;
    csis << a << endl;
    wait();
}

免责声明:此计划是作为学校作业编写的,已经被录入评分。这是我的第一个c ++程序,所以我想了解我的错误。非常感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

您已经定义了这样的运算符[]:

const int operator [] (int) const;

第二个“const”意味着在该方法中你无法修改你的对象。

因此它只适用于获取值,但不适用于设置它们。

尝试删除它,它应该可以工作。

编辑:AS指出Bryan Chen,你还需要返回一个引用和非const,如下所示:

int& operator [] (int subscript)

现在,深入研究一下你的代码,这还不够,因为你有这个方法:

ostream & operator << (ostream & output, const IntArray & array) {
    for (int i = array.low(); i <= array.high(); i++) {
        output << array.name << "[" << i << "] = " << array[i] << endl;
    }
    return output;
}

看看operator []需要处理非const IntArray,但是在那个方法中你的变量“array”是const,所以你需要重写一些代码。

另外,查看其余运算符的相同问题,请记住:只有在不打算从该方法内部修改对象时才创建方法'const',并创建参数'const'仅当您不打算修改该参数时。

答案 1 :(得分:0)

您现有的运算符不允许更改值,因为它返回值int并且因为运算符被声明为const。您不能将值分配给一个对象(包括引用,因为引用只是对象的另一个名称)。

要完成此任务,您需要使用另一个非常量运算符来补充现有运算符,该非常量运算符将返回对(非常量)int的引用:

int & operator[](int index);

由于此运算符将返回引用,因此您可以使用您希望使用的熟悉的a[b] = c语法直接指定返回值。

您不会需要来更改现有的运算符,但我强烈建议您将返回类型从const int更改为int - 无论如何,您都要返回值,所以你要交回副本。这对于const来说是没有意义的,这可能会阻止编译器在比int更复杂的数据类型的情况下删除副本。 (它在这里确实没什么区别,但是我会避免养成按值 const返回的习惯,因为 - 假设存在复制构造函数 - const通过简单地再次复制值,无论如何都可以删除限定符。返回const副本通常没有任何好处,但有几个缺点。)

答案 2 :(得分:0)

既然你也要求指出你的错误,我想评论你应该/可以做的两件事,以使代码更简单:

首先,赋值运算符可以这样写:

IntArray& operator=(IntArray rhs)
{
   std::swap(rhs.a, a);
   std::swap(rhs.b, b);
   std::swap(rhs.size, size);
   std::swap(rhs.num, num);
   std::swap(rhs.name, name);
   return *this;
}

这是有效的,因为你已经为IntArray定义了一个复制构造函数和析构函数,并且它们有望正常工作。所有赋值运算符都在创建一个临时对象,并使用当前对象的内部交换其内部。然后临时模具带有旧数据&#34;,而新数据安全地存在于当前对象中。这称为copy/swap成语。

另请注意,返回的引用为non-const

如果传递const引用而不是对象,则赋值运算符负责初始复制。

IntArray& operator=(const IntArray& orig)
{
   IntArray rhs(orig);
   std::swap(rhs.a, a);
   std::swap(rhs.b, b);
   std::swap(rhs.size, size);
   std::swap(rhs.num, num);
   std::swap(rhs.name, name);
   return *this;
}

前一版本可能更快,因为允许编译器优化传递值的副本。但是,传递const引用的第二种形式是通常所做的 - 请注意,在继续之前需要在函数内部创建临时对象。

其次,您的operator +可以使用operator +=

IntArray operator+(const IntArray& rhs)
{
   IntArray temp(*this);
   return temp += rhs;
}

我们所做的就是创建一个等于当前对象的临时对象。然后我们使用+=添加rhs并返回结果。很好,很简单。请注意,operator +返回一个新的IntArray对象,而不是const IntArray。此外,operator +=应返回对当前对象的引用,而不是bool

为了利用这一点,您的operator +=应该被重写:

IntArray& operator+=(const IntArray& rhs)
{
  //..your current code goes here:
  //...
  return *this;
}

此外,您的operator +=不应该是&#34;错误输出&#34;像那样。您需要尝试添加两个可能不同大小的IntArray来使类更健壮。如果确实存在错误抛出异常。不要返回bool - 完全删除该函数中的return true;return false;。始终返回*this