2010-10-24 13 views
12

Diciamo che ho una classe casella e un utente può creare caselle. Come farlo? Capisco di creare oggetti per className objectName(args); ma come farlo dinamicamente, a seconda dell'input dell'utente?Come creare oggetti di classe dinamicamente?

+3

È possibile fornire un esempio di codice (potenzialmente pseudocode)? –

+0

Creali dove? Puoi memorizzarli in un 'std :: vector', ad esempio, ma questo dipende molto da cosa stai facendo. – GManNickG

+0

Sfortunatamente in C++ non è possibile chiamare dinamicamente un costruttore. L'unico modo è quello di memorizzare oggetti che sono in grado di restituire un oggetto costruito di recente di ciò che si desidera al runtime. Le risposte agli esempi che hai già ricevuto sono completamente pertinenti. –

risposta

5

Il seguente metodo factory crea Box casi dinamicamente in base all'input dell'utente:

class BoxFactory 
{ 
    public: 
    static Box *newBox(const std::string &description) 
    { 
     if (description == "pretty big box") 
     return new PrettyBigBox; 
     if (description == "small box") 
     return new SmallBox; 
     return 0; 
    } 
}; 

Naturalmente, PrettyBigBox e SmallBox entrambi derivano da Box. Dai un'occhiata ai pattern creativi nello C++ design patterns wikibook, poiché probabilmente uno di questi si applica al tuo problema.

2

In C++, è possibile allocare oggetti utilizzando lo storage automatico (stack) e dinamico (heap).

Type variable_name; // variable_name has "automatic" storage. 
        // it is a local variable and is created on the stack. 

Type* pointer_name = NULL; // pointer_name is a "pointer". The pointer, itself, 
          // is a local variable just like variable_name 
          // and is also created on the stack. Currently it 
          // points to NULL. 

pointer_name = new DerivedType; // (where DerivedType inherits from Type). Now 
           // pointer_name points to an object with 
           // "dynamic" storage that exists on the heap. 

delete pointer_name; // The object pointed-to is deallocated. 
pointer_name = NULL; // Resetting to NULL prevents dangling-pointer errors. 

È possibile utilizzare puntatori e heap-allocazione per costruire in modo dinamico gli oggetti come in:

#include <cstdlib> 
#include <iostream> 
#include <memory> 
class Base { 
    public: 
     virtual ~Base(){} 
     virtual void printMe() const = 0; 
    protected: 
     Base(){} 
}; 
class Alpha : public Base { 
    public: 
     Alpha() {} 
     virtual ~Alpha() {} 
     virtual void printMe() const { std::cout << "Alpha" << std::endl; } 
}; 
class Bravo : public Base { 
    public: 
     Bravo() {} 
     virtual ~Bravo() {} 
     virtual void printMe() const { std::cout << "Bravo" << std::endl; } 
}; 
int main(int argc, char* argv[]) { 
    std::auto_ptr<Base> pointer; // it is generally better to use boost::unique_ptr, 
           // but I'll use this in case you aren't familiar 
           // with Boost so you can get up and running. 
    std::string which; 
    std::cout << "Alpha or bravo?" << std::endl; 
    std::cin >> which; 
    if (which == "alpha") { 
     pointer.reset(new Alpha); 
    } else if (which == "bravo") { 
     pointer.reset(new Bravo); 
    } else { 
     std::cerr << "Must specify \"alpha\" or \"bravo\"" << std::endl; 
     std::exit(1); 
    } 
    pointer->printMe(); 
    return 0; 
} 

correlati: the "Factory" object-oriented design pattern

15

La risposta corretta dipende dal numero di classi diverse di cui si desidera per creare le istanze.

Se il numero è enorme (l'applicazione dovrebbe essere in grado di creare un'istanza di qualsiasi classe nell'applicazione), è necessario utilizzare la funzionalità di riflessione di .Net. Ma, ad essere onesti, non sono un grande fan dell'uso della riflessione nella logica di business, quindi consiglierei di non farlo.

Penso che in realtà si abbia un numero limitato di classi per cui si desidera creare istanze. E tutte le altre risposte fanno questa supposizione. Quello di cui hai effettivamente bisogno è un modello di fabbrica. Nel codice seguente Suppongo inoltre che le classi di cui si desidera creare istanze, tutti derivano dalla stessa classe base, diciamo degli animali, in questo modo:

class Animal {...}; 
class Dog : public Animal {...} 
class Cat : public Animal {...} 

Quindi creare una fabbrica di astratto che è un'interfaccia che crea un animale:

class IFactory 
    { 
    public: 
     Animal *create() = 0; 
    }; 

Quindi creare sottoclassi per ciascuno dei diversi tipi di animali. Per esempio. per la classe Dog questo diventerà questo:

class DogFactory : public IFactory 
    { 
    public: 
     Dog *create() {return new Dog();} 
    }; 

E lo stesso per il gatto.

Il metodo DogFactory :: create esegue l'override del metodo IFactory :: create, anche se il loro tipo di reso è diverso. Questo è ciò che viene chiamato tipi di ritorno in co-variante. Questo è permesso fino a quando il tipo di ritorno del metodo della sottoclasse è una sottoclasse del tipo restituito della classe base.

Che ora è possibile fare è mettere le istanze di tutte queste fabbriche in una mappa, in questo modo:

typedef std::map<char *,IFactory *> AnimalFactories 
AnimalFactories animalFactories; 
animalFactories["Dog"] = new DogFactory(); 
animalFactories["Cat"] = new CatFactory(); 

Dopo l'input dell'utente, è necessario trovare il giusto fabbrica, e chiedergli di creare l'istanza dell'animale:

AnimalFactories::const_iterator it=animalFactories.find(userinput); 
if (it!=animalFactories.end()) 
    { 
    IFactory *factory = *it; 
    Animal *animal = factory->create(); 
    ... 
    } 

Questo è il tipico approccio di fabbrica astratta. Ci sono anche altri approcci. Insegnando a me stesso il C++ ho scritto un piccolo articolo su CodeProject. Puoi trovarlo qui: http://www.codeproject.com/KB/architecture/all_kinds_of_factories.aspx.

Buona fortuna.

0

Un modo semplice è utilizzare il vettore. prima, includi libreria vettoriale e crea un oggetto temporaneo come classe.

class temp; 

quindi, fare un vettore per esempio chiamato oggetti con il tipo di classe:

#include <vector> 
. 
. 
vector <class>objects; 

Quindi è possibile aggiungere un ciclo per l'aggiunta di un esempio oggetto Spazio, ho una classe denominata temperatura che ha una funzione chiamata input e voglio aggiungere:

while(1){ 
     temp.input(); 
     objects.push_back(temp); 
     } 

ora avete una classe dinamica. per accedere agli oggetti è possibile utilizzare in questo modo:

objects[i]; 

e se si desidera eliminare un oggetto, è sufficiente utilizzare in questo modo: 1.Trovare vostra posizione oggetto nel vettore. 2.MODIFICA importo dell'ultimo blocco del vostro vettore con quello e rimuovere l'ultimo blocco:

objects[location of the object you want to remove]=objects[location of your last block]; 
objects.pop_back(); 

se si desidera conoscere la posizione dell'ultimo blocco del vettore fare questo:

int lastblock; 
lastblock=(objects.size()-1); 

nota: è possibile utilizzare i vettori come un array.

Problemi correlati