2010-09-15 2 views
19

Как вернуть многомерный массив, скрытый в частном поле?C++ Возвращаемый массив многомерности из функции

class Myclass { 
private: 
int myarray[5][5]; 
public: 
int **get_array(); 
}; 

........ 

int **Myclass::get_array() { 
return myarray; 
} 

не может преобразовать int (*)[5][5] в int** в обратном test.cpp/Polky/ЦСИ строка 73 C/C++ Проблема

+4

Что такое сетка? разве это не «майаррей»? – woodstok

+3

Возвращение прямой ссылки на частного участника может не всегда быть хорошей идеей - вы эффективно нарушаете инкапсуляцию этим, позволяя кому-либо получить доступ и изменить вашего частного участника. Это может быть или не быть приемлемым в вашем дизайне. –

+0

@MIkhail: Поскольку justin не был онлайн с того момента, как он опубликовал этот вопрос, я взял на себя смелость исправить это. – sbi

ответ

-1

Изменение ИНТ, чтобы ИНТ [] [] s или попробуйте использовать Int [,] вместо ?

+1

'int [,]' недопустимо. C++ –

+3

... и 'int [] []' также не должны быть действительными. В этом случае важно понять разницу между массивами и указателями. – visitor

+2

@David: Фактически, 'new int [5, 5]' является допустимым C++, он просто не делает то, что можно было бы подумать, - это то же самое, что и 'new int [5]' благодаря оператору запятой :) – fredoverflow

-1
int **Myclass::get_array() { 
return (int**)myarray; 
} 
+1

Нет. Если вы используете это, вы будете переинтерпретировать элементы массива в качестве указателей. –

+0

@Mike Seymour, и это правда, если вы рассматриваете каждую строку как int * (как и каждый вектор целых чисел, который является int *). – rkellerm

4

Чтобы вернуть указатель на свой массив элемента массива, тип Необходим int (*)[5], не int **:

class Myclass { 
private: 
    int myarray[5][5]; 
public: 
    int (*get_array())[5]; 
}; 

int (*Myclass::get_array())[5] { 
    return myarray; 
} 
1

мне удалось заставить эту функцию работать в C++ 0x, используя автоматический тип вычет , Однако я не могу заставить это работать без этого. Родные C массивы не очень хорошо поддерживаются в C++ - их синтаксис чрезвычайно отвратителен. Вы должны использовать класс-оболочку.

template<typename T, int firstdim, int seconddim> class TwoDimensionalArray { 
    T data[firstdim][seconddim]; 
public: 
    T*& operator[](int index) { 
     return data[index]; 
    } 
    const T*& operator[](int index) const { 
     return data[index]; 
    } 
}; 
class Myclass { 
public: 
    typedef TwoDimensionalArray<int, 5, 5> arraytype; 
private: 
    arraytype myarray; 
public: 
    arraytype& get_array() { 
     return myarray; 
    } 
}; 

int main(int argc, char **argv) { 
    Myclass m; 
    Myclass::arraytype& var = m.get_array(); 
    int& someint = var[0][0]; 
} 

Этот код компилируется просто отлично. Вы можете получить предварительно написанный класс-оболочку внутри Boost (boost :: array), который поддерживает весь shebang.

+0

Не компилируется с GCC: первые данные возврата [index] делают неконстантную ссылку из rvalue, говорит он. – Cubbi

+0

И в этом случае должен быть возвращен пустой указатель, а не ссылка на указатель. В противном случае мы, по крайней мере, получим большую удобочитаемость. Один незначительный момент: зачем использовать 'int' для фактических типов шаблонов? Я думаю, что что-то, что не может быть отрицательным, будет лучше выражено с помощью целых чисел без знака. –

+0

data [index] - это значение lvalue, а не rvalue, как * ptr - значение lvalue. Не то, чтобы ссылка действительно необходима, я думаю, что это из предыдущей версии кода, вы, вероятно, могли бы ее удалить. – Puppy

22

Двумерный массив не распадается на указатель на указатель на int. Он распадается на указатель на массивы ints - то есть только первое измерение распадается на указатель. Указатель не указывает на указатели на int, которые при увеличении увеличивается на величину указателя, но на массивы из 5 целых чисел.

class Myclass { 
private: 
    int myarray[5][5]; 
public: 
    typedef int (*pointer_to_arrays)[5]; //typedefs can make things more readable with such awkward types 

    pointer_to_arrays get_array() {return myarray;} 
}; 

int main() 
{ 
    Myclass o; 
    int (*a)[5] = o.get_array(); 
    //or 
    Myclass::pointer_to_arrays b = o.get_array(); 
} 

указатель на указатель (int**) используется, когда каждый подмассив выделяется отдельно (то есть, вы изначально есть массив указателей)

int* p[5]; 
for (int i = 0; i != 5; ++i) { 
    p[i] = new int[5]; 
} 

Здесь мы имеем массив из пяти указателей, каждый из которых указывает на первый элемент в отдельном блоке памяти, всего 6 различных блоков памяти.

В двумерный массиве вы получите один непрерывный блок памяти:

int arr[5][5]; //a single block of 5 * 5 * sizeof(int) bytes 

Вы должны увидеть, что расположение памяти этих вещей совершенно разные, и, следовательно, эти вещи не могут быть возвращены и прошло так же.

+0

+1 спасибо, отличный ответ –

2

Как вернуть многомерный массив, скрытый в частном поле?

Если это должно быть скрыто, почему вы его возвращаете в первую очередь?

В любом случае вы не можете возвращать массивы из функций, но вы можете вернуть указатель на первый элемент. Что такое первый элемент массива 5x5 из ints? Массив из 5 целых чисел, конечно:

int (*get_grid())[5] 
{ 
    return grid; 
} 

В качестве альтернативы, вы можете вернуть весь массив по ссылке:

int (&get_grid())[5][5] 
{ 
    return grid; 
} 

...добро пожаловать в C декларатор синтаксис ад ;-)

Могу я предложить std::vector<std::vector<int> > или boost::multi_array<int, 2> вместо этого?

16

Существует два возможных типа, которые вы можете вернуть для обеспечения доступа к вашему внутреннему массиву. Старый стиль C будет возвращать int *[5], так как массив легко распадается на указатель на первый элемент, который имеет тип int[5].

int (*foo())[5] { 
    static int array[5][5] = {}; 
    return array; 
} 

Теперь вы можете вернуть правильную ссылку на внутренний массив, самый простой синтаксис будет через ЬурейиЙ:

typedef int (&array5x5)[5][5]; 
array5x5 foo() { 
    static int array[5][5] = {}; 
    return array; 
} 

или чуть более громоздкий без ЬурейеГо:

int (&foo())[5][5] { 
    static int array[5][5] = {}; 
    return array; 
} 

Преимущество версии C++ заключается в том, что фактический тип поддерживается, а это значит, что фактический размер массива известен со стороны вызывающих абонентов.

+0

+1 для версии на C++ (с правильным typedef) –

+1

Хотя будьте осторожны, как вы используете эти typedefs, иногда: 'delete [] new array5x5()' (выглядит как новый, но это действительно новый []). – 2010-11-13 10:45:34