2010-09-15 3 views
19

Come si restituisce una matrice multidimensionale nascosta in un campo privato?C++ Restituzione di una matrice multidimensionale dalla funzione

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

........ 

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

non può convertire int (*)[5][5]-int** in test.cpp cambio/Polky/src linea 73 C/C++ Problema

+4

cos'è la griglia? non dovrebbe essere "myarray"? – woodstok

+3

Restituire un riferimento diretto a un membro privato potrebbe non essere sempre una buona idea: in questo modo si interrompe l'incapsulamento, consentendo a chiunque di accedere e modificare il proprio membro privato. Questo può o non può essere accettabile nel tuo progetto. –

+0

@MIkhail: Dal momento che justin non è online da quando ha postato questa domanda, mi sono preso la libertà di sistemarlo. – sbi

risposta

-1

Modifica del int a int [] [s '] o provare a utilizzare int [,] invece ?

+1

'int [,]' non è valido C++ –

+3

... e 'int [] []' non dovrebbe essere valido neanche. In questo caso è importante capire la differenza tra array e puntatori. – visitor

+2

@David: In realtà, 'new int [5, 5]' è C++ valido, semplicemente non fa quello che si potrebbe pensare - è lo stesso di 'new int [5]' grazie all'operatore virgola :) – fredoverflow

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

No. Se lo usi, reinterpreteresti gli elementi dell'array come puntatori. –

+0

@Mike Seymour, ed è vero se consideri che ogni riga sia int * (come ogni vettore di interi che è int *). – rkellerm

4

Per restituire un puntatore alla propria matrice di membro di matrice, il tipo è necessario int (*)[5], non int **:

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

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

sono riuscito a fare questa funzione opera in C++ 0x usando il tipo deduzione automatica . Tuttavia, non posso farlo funzionare senza quello. Gli array Native C non sono supportati molto bene in C++ - la loro sintassi è estremamente orribile. Dovresti usare una classe wrapper.

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]; 
} 

Questo codice viene compilato correttamente. È possibile ottenere una classe wrapper pre-scritta all'interno di Boost (boost :: array) che supporta l'intero shebang.

+0

Non si compila con GCC: i primi dati di ritorno [indice] rendono un riferimento non const da un valore, dice. – Cubbi

+0

E questo è il caso, si dovrebbe restituire un puntatore nudo, non un riferimento a un puntatore. Altrimenti, almeno otteniamo molta leggibilità. Un punto minore: perché usare 'int' per i tipi di template attuali? Qualcosa che non può essere negativo sarebbe meglio espresso con un tipo intero senza segno, credo. –

+0

data [indice] è un lvalue, non un rvalue, molto simile a * ptr è un lvalue. Non che il riferimento sia veramente necessario, penso che provenga da una versione precedente del codice, probabilmente lo si potrebbe rimuovere. – Puppy

22

Un array bidimensionale non decadono in un puntatore del puntatore agli inte. Decompone in un puntatore agli array di interi, ovvero, solo la prima dimensione decade in un puntatore. Il puntatore non punta ai puntatori int, che all'avanzamento incrementato della dimensione di un puntatore, ma a matrici di 5 numeri interi.

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(); 
} 

Un puntatore a puntatore (int**) viene utilizzato quando ogni sottoarray viene allocata separatamente (cioè, è in origine un array di puntatori)

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

Qui abbiamo un array di cinque puntatori, ognuno punta al primo elemento in un blocco di memoria separato, complessivamente 6 blocchi di memoria distinti.

In un array bidimensionale si ottiene un unico blocco contiguo di memoria:

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

si dovrebbe vedere che il layout di memoria di queste cose sono completamente diversi, e quindi queste cose non possono essere restituiti e superato il stessa strada.

+0

+1 grazie, ottima risposta –

2

Come restituire un array multidimensionale nascosto in un campo privato?

Se si suppone di essere nascosto, perché stai tornando in primo luogo?

In ogni caso, non è possibile restituire gli array dalle funzioni, ma è possibile restituire un puntatore al primo elemento. Qual è il primo elemento di un array 5x5 di ints? Una serie di 5 interi, naturalmente:

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

In alternativa, si potrebbe tornare l'intero array per riferimento:

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

...benvenuto a C dichiarator sintassi inferno ;-)

Posso suggerire std::vector<std::vector<int> > o boost::multi_array<int, 2> invece?

16

Ci sono due tipi possibili che è possibile restituire per fornire l'accesso al proprio array interno. Il vecchio stile C restituirà int *[5], in quanto l'array si decomporrà facilmente in un puntatore al primo elemento, che è di tipo int[5].

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

Ora, si può anche restituire un adeguato riferimento alla matrice interna, la sintassi più semplice sarebbe attraverso un typedef:

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

o un po 'più ingombrante senza la typedef:

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

Il vantaggio della versione C++ è che il tipo effettivo viene mantenuto e ciò significa che la dimensione effettiva della matrice è nota a chi chiama.

+0

+1 per la versione C++ (con il typedef corretto) –

+1

Anche se fai attenzione a come usi quei typedef, a volte: 'delete [] new array5x5()' (sembra nuovo, ma è davvero nuovo []). –