带自定义类的C ++动态2D数组

时间:2014-04-29 20:27:36

标签: c++ arrays pointers operator-overloading composition

该程序的目标是从一维数组类创建一个复合二维数组类,利用指针和operator[]在主程序中使用。我们被告知让[][]像标准2D阵列一样工作。我得到它进行编译但是当我使用2DArray类时崩溃了。我知道目标是理解指针,但我认为运算符[]给了我最大的麻烦。任何见解都将是最受欢迎的。

编辑:使用标准数组查找Works。但是,如果我能以一种简单的方式利用课程,我会很高兴,例如:

#include <iostream>
#include "MyArray.h"
#include "TwoDArray.h"

using namespace std;

int main()
{
TwoDArray test(4,5);
cout << "Test output:  "<< test[3][2] << endl;
return 0;
}

以下是2D数组类实现的代码:

#include <iostream>
#include <cstdlib>
#include "TwoDArray.h"
#include "MyArray.h"


TwoDArray::TwoDArray()
{
    //Default Constructor
    row = 10;
    col = 10;
    MyArray** p = new MyArray* [10];
    for (int i = 0; i < 10; i++)
    {
        p[i] = new MyArray[10];
    }
}

TwoDArray::TwoDArray (int r, int c)
{
    row = r;
    col = c;
    MyArray** p = new MyArray* [col];
    for (int i = 0; i < col; i++)
    {
        p[i] = new MyArray[row];
    }
}

TwoDArray::~TwoDArray() //Destructor 
{
    for (int i = 0; i < row; i++)
    {
        delete [] &p[i];
    }
    delete [] p;
}

MyArray & TwoDArray::operator[] (int pos)
{
    if( pos < 0 || pos >= col )
    {
        cout << "Illegal index, pos = " << pos << endl;
    }
    return *p[pos];
}

除了教师给出的1DArray(MyArray)类实现:

#include <iostream>
#include <cstdlib>
#include "MyArray.h"    // "" around header means "look in current directory first"

// default to an array of 10 integers, fill with 0
MyArray::MyArray()
{
    int i;
    _a = new int[10];    // new allocates RAM from system heap, [] says allocate an array
    _n = 10;
    for( i = 0; i < 10; i++ )
    {
        _a[i] = 0;       // initialize array to all 0
    }
}

// allocate array of a size requested by the client if legal, fill with 0
MyArray::MyArray( int num )
{
    int i;
    if( num <= 0 ) // if illegal, set to default
    {
        num = 10;
    }
    _a = new int[num];
    _n = num;
    for( i = 0; i < num; i++ )
    {
        _a[i] = 0;       // initialize array to all 0
    }
}

// copy constructor - invoke deep copy asignment
MyArray::MyArray( const MyArray &m )
{
   *this = m;
}

// destructor - needed to deallocate RAM allocated in constructors
MyArray::~MyArray()
{
    delete[] _a;
}

// get value at position pos
int &MyArray::At( int pos )
{
    if( pos < 0 || pos >= _n )
    {
        cout << "Illegal index, pos = " << pos << endl;
        exit( -1 );
    }
    return _a[pos];
}

// get value at position pos using [] indexing operator
int & MyArray::operator []( int pos )
{
    cout << "1D [] pos = " << pos << "_n is " << _n << endl;
    if( pos < 0 || pos >= _n )
    {
        cout << "Illegal index, pos = " << pos << endl;
        exit( -1 );
    }
    return _a[pos];
}

// return size, const here means it cannot change self
int MyArray::size( void ) const
{
    return _n;
}

// deep copy - REQUIRED if allocated RAM is used by object!
MyArray &MyArray::operator =( const MyArray &rhs )
{
    int i;
    if( &rhs == this ) // assignment to self?
    {
        return *this;  // if so, don't assign, just return self
    }
    if( rhs._n != _n )   // rhs not the same size as myself?
    {
        delete[] _a;    // yes, clear out my data and reallocate to match
        _a = new int[rhs._n];
        _n = rhs._n;
    }
    for( i = 0; i < rhs._n; i++ )  // copy all elements
    {
        _a[i] = rhs._a[i];
    }
    return *this;      // allow a = b = c; assignment
}

5 个答案:

答案 0 :(得分:1)

你的析构函数有点过分。试试这个:

TwoDArray::~TwoDArray() //Destructor 
{
    delete [] p;
}

您还没有存储您在构造函数中分配的指针。您将分配的内存分配给在堆栈中声明的指针。不是您的会员p

此外,您还要分配一个可以制作3D阵列的2D阵列数组

在您的构造函数中为您的成员p分配一组MyArray,如下所示:

TwoDArray::TwoDArray()
{
    //Default Constructor
    row = 10;
    col = 10;
    p = new MyArray[row]; // where p is a MyArray* member of TwoDArray
    for (int i = 0; i < row; i++)
    {
        p[i] = MyArray(col);
    }
}

TwoDArray::TwoDArray (int r, int c)
{
    row = r;
    col = c;
    p = new MyArray[row]; // where p is a MyArray* member of TwoDArray
    for (int i = 0; i < row; i++)
    {
        p[i] = MyArray(col);
    }
}

答案 1 :(得分:1)

如果MyArray本身是一维数组,那么我的错误就是用MyArray初始化一个二维数组。我没有描述细节,但我认为你需要做这样的事情 -

TwoDArray::TwoDArray()
{
//Default Constructor
row = 10;
col = 10;
MyArray* p = new MyArray [10];
for (int i = 0; i < 10; i++)
{
    p[i] = new MyArray(10);
} }

TwoDArray::TwoDArray (int r, int c)
{
row = r;
col = c;
MyArray* p = new MyArray [col];
for (int i = 0; i < col; i++)
{
    p[i] = new MyArray(row);
}
}

注意我用一维数组改变了2D初始化,每个数组都是一个MyArray对象,它本身就是一个数组 - 因此就是二维数组

答案 2 :(得分:0)

如果我理解您的代码正确,MyArray代表TwoDArray的一行。在这种情况下,TwoDArray的构造函数不会使用正确的参数创建MyArray个对象。

你有:

TwoDArray::TwoDArray()
{
    //Default Constructor
    row = 10;
    col = 10;
    MyArray** p = new MyArray* [10];
    for (int i = 0; i < 10; i++)
    {
        p[i] = new MyArray[10];
    }
}

首先,我会更改使用10来恰当地使用rowcol

TwoDArray::TwoDArray()
{
    //Default Constructor
    row = 10;
    col = 10;
    MyArray** p = new MyArray* [row];
    for (int i = 0; i < 10; i++)
    {
        p[i] = new MyArray[col]; // This is a problem line. You are creating col
                                 // MyArray objects. I think you should create one
                                 // MyArray object with col items in it.

        p[i] = new MyArray(col); // This is what you want.
    }
}

但真正的问题是你有:

    MyArray** p = new MyArray* [row];

这是一个局部变量。从函数返回时它会消失。成员变量p仍然未初始化。你的意思是:

    p = new MyArray* [row];

您可以类似地更改其他构造函数。

cppguy已经指出了析构函数的问题。

答案 3 :(得分:0)

你的TwoDArray构造函数有缺陷:     for(int i = 0; i&lt; 10; i ++)     {         p [i] =新的MyArray [10];     }

你正在创造一个3D阵列!! 将其更改为p [i] = new MyArray(10);

并从那里继续!

答案 4 :(得分:0)

您的代码仍然存在一些问题。

Issue 1:

如果TwoDArray是const对象,则不会编译operator []。这是一个例子

void foo(const TwoDArray& arr)
{
   int x = arr[0][0];  // error.  operator [] must be const
}

在这里使用const TwoDArray是完全合理的,因为你没有改变数组的内部。因此,您需要重载operator []两次,一次用于const对象,另一次用于非const。所以第二个重载应该是这样的:

const MyArray & TwoDArray::operator[] (int pos) const
{
    if( pos < 0 || pos >= col )
    {
        cout << "Illegal index, pos = " << pos << endl;
    }
    return *p[pos];
}

但是,这里仍然存在一个问题,我将在下面的Issue 3中展示。

Issue 2:如果this失败,您的分配操作符将损坏new[]

在分配运算符中,您调用delete[] _a。如果后续调用new []会引发异常,会发生什么?您现在已经损坏了对象,因为您删除了内存,因此无法恢复已删除的数据。

至少在你的实施中,应该做的是

  1. 首先分配新内存,然后分配给临时指针
  2. 将数据从传入的对象移动到新的内存
  3. 删除旧内存(在这种情况下,这是您最终调用delete [] _a;
  4. 的位置
  5. 将步骤1中的临时指针分配给_a
  6. 这样,如果第1步失败,将抛出异常,并且您的对象不会被破坏。

    Issue 3:在您的operator []中,如果进行了越界访问,您仍然可以继续执行非法访问。

    如果你想让这个班级的用户在他们提供越界访问权限的情况下用脚射击,那么我认为你应该删除cout消息然后继续并允许非法行为访问。如果您确实想要进行边界检查访问,请使用可以输出的at()函数和越界访问的throw an exception

    请注意,这就是std::vector执行操作的方式 - 取消选中operator [],同时选中std::vector::at()并将导致错误。

    Issue 4:。文体 - 小心用下划线开始变量名。

    为编译器的实现保留了未标记的名称。我知道有些情况下强调的名字是安全的,但我总是保证安全,并且永远不会引入以下划线开头的名字。

    Issue 5:你想使用operator []得到一个二维数组吗? 有人反对使用[] []来表示二维矩阵,而是使用operator()来表示索引。

    见这里:http://www.parashift.com/c++-faq/matrix-subscript-op.html