2011-12-20 17 views
11

Sto tentando di dichiarare un array con una classe personalizzata. Quando ho aggiunto un costruttore alla classe, il mio compilatore si lamenta del fatto che non esiste "Costruttore corrispondente per l'inizializzazione del nome [3]".Come si dichiara un array con una classe personalizzata?

Ecco il mio programma:

#include <iostream> 

using namespace std; 

class name { 
    public: 
    string first; 
    string last; 

    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 

int main (int argc, const char * argv[]) 
{ 

    const int howManyNames = 3; 

    name someName[howManyNames]; 

    return 0; 
} 

Cosa posso fare per rendere questa corsa, e quello che sto facendo male?

risposta

16

È necessario fornire un costruttore predefinito. Mentre si è in esso, fissare la vostra altro costruttore, troppo:

class Name 
{ 
public: 
    Name() { } 
    Name(string const & f, string const & l) : first(f), last(l) { } 
    //... 
}; 

In alternativa, è necessario fornire i inizializzatori:

Name arr[3] { { "John", "Doe" }, { "Jane", "Smith" }, { "", "" } }; 

Quest'ultimo è concettualmente preferibile, perché non c'è ragione che la classe dovrebbe avere una nozione di uno stato "predefinito". In tal caso, è sufficiente che abbia per fornire un inizializzatore appropriato per ogni elemento dell'array.

Gli oggetti in C++ non possono mai essere in uno stato non definito; se ci pensi, tutto dovrebbe diventare molto chiaro.


Un'alternativa è quella di utilizzare una dinamica contenitore , anche se questo è diverso da quello che hai chiesto:

std::vector<Name> arr; 
arr.reserve(3); // morally "an uninitialized array", though it really isn't 

arr.emplace_back("John", "Doe"); 
arr.emplace_back("Jane", "Smith"); 
arr.emplace_back("", ""); 

std::vector<Name> brr { { "ab", "cd" }, { "de", "fg" } }; // yet another way 
+0

POD può essere in uno stato mal definito;) – fredoverflow

+1

@FredOverflow: Sono non "mal definiti" - sono "non inizializzato", che è concettualmente ben definito, con la semantica che non devi leggerli. –

+0

Ok, quindi quale sarebbe un esempio di qualcosa che * può * essere in uno stato mal definito? – fredoverflow

3

È necessario un parameterless constructor per poter creare un'istanza della classe. Il tuo costruttore attuale richiede due parametri di stringa di input.

Normalmente C++ implica che tale costruttore (= costruttore senza parametri predefinito) se c'è nessun altro costruttore dichiarato. Dichiarando il tuo primo costruttore con due parametri, si sovrascrive questo comportamento predefinito e ora si deve dichiarare esplicitamente questo costruttore.

Ecco il codice di lavoro: (. A proposito, è necessario includere per rendere il codice compilabile)

#include <iostream> 
#include <string> // <-- you need this if you want to use string type 

using namespace std; 

class name { 
    public: 
    string first; 
    string last; 

    name(string a, string b){ 
    first = a; 
    last = b; 

    } 

    name() // <-- this is your explicit parameterless constructor 
    {} 

}; 

int main (int argc, const char * argv[]) 
{ 

    const int howManyNames = 3; 

    name someName[howManyNames]; 

    return 0; 
} 

Un modo alternativo è quello di inizializzare le istanze in modo esplicito sulla dichiarazione

name someName[howManyNames] = { {"Ivan", "The Terrible"}, {"Catherine", "The Great"} }; 
4

Per default-inizializzare un array di T s, T deve essere costruibile di default . Normalmente il compilatore ti fornisce un costruttore predefinito gratuito. Tuttavia, dal momento che hai dichiarato tu stesso un costruttore, il compilatore non genera un costruttore predefinito.

Le opzioni disponibili:

  • aggiungere un costruttore predefinito per nome, se questo ha un senso (io non la penso così, ma non so il dominio del problema);
  • inizializza tutti gli elementi dell'array su dichiarazione (è possibile farlo perché name è un aggregato);

    name someName[4] = { { "Arthur", "Dent" }, 
             { "Ford", "Prefect" }, 
             { "Tricia", "McMillan" }, 
             { "Zaphod", "Beeblebrox" } 
            }; 
    
  • uso un std::vector invece, e aggiungere solo elemento quando si è li costruito.

1

è sufficiente aggiungere un costruttore di default per la classe a guardare come questo:

class name { 
    public: 
    string first; 
    string last; 

    name() { 
    } 

    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 
1

La classe:

class name { 
    public: 
    string first; 
    string last; 

    name() { } //Default constructor. 

    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 

ha un esplicito costruttore che richiede due stringhe parametri. Le classi senza costrutto scritto esplicitamente ottengono i costruttori predefiniti senza alcun parametro. L'aggiunta di quella esplicita ha impedito al compilatore di generare per te quel costruttore di default.

Quindi, se si desidera creare una matrice di oggetti non inizializzati, aggiungere un costruttore predefinito alla classe in modo che il compilatore sappia come crearli senza fornire quei due parametri di stringa - vedere la riga commentata sopra.

1

Per creare una matrice di oggetti, gli oggetti necessitano di un costruttore che non accetta alcun parametro (che crea una forma predefinita dell'oggetto, ad esempio con entrambe le stringhe vuote). Questo è ciò che significa il messaggio di errore. Il compilatore genera automaticamente un costruttore che crea un oggetto vuoto a meno che ci siano altri costruttori.

Se ha senso per gli elementi dell'array da creare vuoti (nel qual caso i membri acquisiscono i valori predefiniti, in questo caso, stringhe vuoto), è necessario:

-Scrivere uno vuoto:

class name { 
    public: 
    string first; 
    string last; 

    name() { } 
    name(string a, string b){ 
    first = a; 
    last = b; 
    } 
}; 

-Oppure, se non è necessario, rimuovere il costruttore esistente.

Se una versione "vuota" della classe non ha senso, non esiste una buona soluzione per fornire i parametri di inizializzazione a tutti gli elementi dell'array in fase di compilazione. È possibile:

  • avere un costruttore di creare una versione vuota della classe in ogni caso, e una funzione di init() che fa la vera inizializzazione
  • Utilizzare un vector, e inizializzazione creare gli oggetti e inserirle nella vector, o usando vector::insert o un ciclo, e fidati che non farlo in fase di compilazione non importa.
  • Se non è possibile copiare l'oggetto, è possibile utilizzare un oggetto/vettore di puntatori intelligenti sull'oggetto e allocarli all'inizializzazione.
  • Se è possibile utilizzare C++ 11, penso (?) è possibile utilizzare gli elenchi di inizializzatori per inizializzare un vettore e inizializzarlo (non sono sicuro che funzioni con qualsiasi contructor o solo se l'oggetto è creato da un singolo valore di un altro tipo). Ad esempio: .
std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" }; 

`

Problemi correlati