是否可以使用运算符重载按索引分配用户定义的数组?-C++
Is it possible to assign a user-defined Array by index with operator overloading? - C++
问题:当我尝试按索引分配 IntArray 对象时,出现以下错误:
"表达式不可分配。"
该错误由 iadrv.cpp 中的以下代码行生成:
IntArray a(10);
for(int i = a.low(); i <= a.high(); i++)
a[i] = i * 10;
我可以像这样将整个 IntArray 对象分配给另一个对象,a = b;
,但是当特定索引被引用到"表达式不可分配"错误时,会发生"表达式不可分配"错误。
编辑:我从大多数函数中删除了const
声明,并且不再收到"表达式不可分配"错误。但是,setName 现在给出错误:
"ISO C++ 11 不允许从字符串文字转换为'char *'"
此错误是由 iadrv.cpp 中的以下代码引起的:
a.setName("a");
程序说明:
我写了一个类 IntArray(C++),其中重载了以下运算符:
- "[ ]" : 允许索引范围检查
- "=" :允许数组分配
- "+" :允许将两个数组的总和分配给第三个数组
- "+=" :允许将两个数组的总和分配给第一个数组
- "<<":允许输出数组的内容
该程序还包括以下功能:
- setName :设置 IntArray 对象的名称
- getName :返回 IntArray 对象的名称
- 低:返回最小的合法索引
- 高:返回最大的合法索引
- 长度 : 返回元素数
驱动程序(iadrv.cpp,iadrv.h)将在IntArray类(IntArray.cpp,IntArray.h)上运行测试,以确定是否所有运算符都正确重载。
注意:对于每个数组测试数据,驱动程序将简单地将在每个数组初始化或修改并输出其内容后,数组索引立即为 10。当程序遇到运行时错误时,它应该使用适当的诊断"模拟"停止,而不是实际停止程序。
守则:
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++ 程序,所以我想了解我的错误。衷心感谢您的帮助。
你已经像这样定义了你的运算符[]:
const int operator [] (int) const;
第二个"const"意味着在该方法中你不能修改你的对象。
因此,它仅适用于获取值,而不适用于设置值。
尝试删除它,它应该可以工作。
编辑:正如Bryan Chen所指出的,您还需要返回引用和非常量,如下所示:
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[] 需要在非常量 IntArray 上工作,但在该方法中,你的变量"array"是 const,所以你需要重写更多的代码。
另外,在其他运算符中寻找相同的问题,请记住:仅当您不打算从该方法内部修改对象时,您才创建方法"const",并且仅当您不打算修改该参数时才创建参数"const"。
现有运算符不允许更改值,因为它返回 int
by 值,并且运算符声明为 const。 不能分配给值,只能分配给对象(包括引用,因为引用只是对象的另一个名称)。
要实现这一点,你需要用另一个非常量运算符来补充你现有的运算符,它返回对(非常量)int
的引用:
int & operator[](int index);
由于此运算符将返回引用,因此可以使用要使用的熟悉的a[b] = c
语法直接分配给返回值。
您不需要更改现有的运算符,但我强烈建议将返回类型从 const int
更改为仅 int
- 无论如何您都是按值返回的,因此您要交回一份副本。 这是没有意义的,这可能会阻止编译器在数据类型比int
更复杂的情况下省略副本。 (这里并没有太大区别,但我会避免养成按值和常量返回的习惯,因为 - 假设存在复制构造函数 - 无论如何都可以通过简单地再次复制值来删除 const 限定符。返回 const 副本通常没有任何好处,但有几个缺点。
既然你也要求指出你的错误,我想评论一下你应该/可以做的两件事,以使代码更简单:
首先,赋值运算符可以这样写:
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
定义了复制构造函数和析构函数,并且希望它们能够正常工作。 赋值运算符所做的只是创建一个临时对象,并将其内部与当前对象的内部交换。 然后临时数据与"旧数据"一起死亡,而新数据安全地在当前对象中。 这被称为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 +=
不应该像那样"出错"。 您需要通过尝试添加两个大小可能不同的IntArray
来使类更加健壮。 如果确实存在错误,则引发异常。 不要返回布尔值 - 从函数中删除return true;
和return false;
。 始终返回*this
。
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- Visual C++(VS2017)中用户定义的转换不明确
- 使用用户定义的参数调用future/async并调用类方法
- 带有用户定义类的c++折叠表达式
- g++用户定义的动态链接库上的全局new和delete运算符
- 直接在 unordered_map 的方法中使用哈希,而不是生成哈希的用户定义对象
- 修改"std::set"中用户定义类型的值
- 参数包构造函数在类模板中隐藏用户定义的转换
- MAKE:找不到包含的用户定义的头文件?
- C++:用户定义的显式类型转换函数错误
- 是否有解决方法可以在 c++ 中为 short 定义用户定义的文字?
- 从 QAbstractItemModel 返回自定义用户类型
- 无法引用自定义用户控件
- Lua:为自定义用户数据提供一个字符串方法
- 是否可以在visualstudio调试窗口中定义用户定义的变量
- 如何在编写自定义用户操作时引用内置操作
- C++自定义用户输入调用变量
- 不能定义用户定义的字面值