2010-10-24 15 views
12

Nehmen wir an, ich habe eine Klasse Box, und ein Benutzer kann Boxen erstellen. Wie es geht? Ich verstehe, dass ich Objekte von className objectName(args); erstellen, aber wie es dynamisch zu tun, abhängig von der Benutzereingabe?Wie erstellt man Klassenobjekte dynamisch?

+3

Können Sie ein (möglicherweise Pseudocode) Code Beispiel geben? –

+0

Erstelle sie wo? Sie können sie zum Beispiel in einem 'std :: vector' speichern, aber das hängt wirklich davon ab, was Sie tun. – GManNickG

+0

Leider in C++ können Sie einen Konstruktor nicht dynamisch aufrufen. Die einzige Möglichkeit besteht darin, Objekte zu speichern, die zur Laufzeit ein neu konstruiertes Objekt zurückgeben können. Die Beispiele, die Sie bereits erhalten haben, sind vollständig relevant. –

Antwort

5

Die folgende Factory-Methode erstellt Box Instanzen auf Benutzereingaben dynamisch basierend:

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

Natürlich PrettyBigBox und SmallBox ableiten beide aus Box. Werfen Sie einen Blick auf die kreativen Muster in der C++ design patterns wikibook, wie einer von ihnen wahrscheinlich auf Ihr Problem zutrifft.

2

In C++ ist es möglich, Objekte mit automatischen (Stapel) und dynamischen (Heap) Speicher zuzuweisen.

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. 

Sie können mit Zeiger und Heap-Zuweisung dynamisch Objekte konstruieren, wie 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; 
} 

Verwandte: the "Factory" object-oriented design pattern

15

Die richtige Antwort ist abhängig von der Anzahl der verschiedenen Klassen, von denen Sie wollen um die Instanzen zu erstellen.

Wenn die Anzahl sehr groß ist (die Anwendung sollte in der Lage sein, eine Instanz einer beliebigen Klasse in Ihrer Anwendung zu erstellen), sollten Sie die Reflexionsfunktion von .Net verwenden. Aber um ehrlich zu sein, ich bin kein großer Fan der Reflexion in der Geschäftslogik, also rate ich dazu, dies nicht zu tun.

Ich denke, dass Sie in Wirklichkeit eine begrenzte Anzahl an Klassen haben, für die Sie Instanzen erstellen möchten. Und alle anderen Antworten machen diese Annahme. Was Sie wirklich brauchen, ist ein Fabrikmuster. Im nächsten Code gehe ich davon aus, dass die Klassen, von denen Sie Instanzen erstellen möchten, werden alle von der gleichen Basisklasse ableiten, lassen Sie uns Tier sagen, wie folgt aus:

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

Dann ein abstraktes Werk schaffen, das ist eine Schnittstelle, Erzeugt ein Tier:

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

Dann erstellen Unterklassen für jede der verschiedenen Arten von Tieren. Z.B. für die Hundeklasse wird dies so:

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

Und das gleiche für die Katze.

Die DogFactory :: create-Methode überschreibt die IFactory :: create-Methode, auch wenn ihr Rückgabetyp unterschiedlich ist. Dies nennt man co-variante Rückgabetypen. Dies ist zulässig, solange der Rückgabetyp der Methode der Unterklasse eine Unterklasse des Rückgabetyps der Basisklasse ist.

Was Sie jetzt tun können, ist Instanzen all diese Fabriken in eine Karte setzen, wie folgt aus:

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

Nach der Benutzereingabe, müssen Sie die richtige Fabrik zu finden, und sie auffordern, die Instanz zu erstellen des Tieres:

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

Dies ist der typische abstrakte Fabrikansatz. Es gibt auch andere Ansätze. Als ich C++ selbst unterrichtete, schrieb ich einen kleinen CodeProject-Artikel darüber. Sie können es hier finden: http://www.codeproject.com/KB/architecture/all_kinds_of_factories.aspx.

Viel Glück.

0

Ein einfacher Weg ist, Vektor zu verwenden. Als erstes fügen Sie die Vektorbibliothek hinzu und erstellen Sie ein temporäres Objekt als Ihre Klasse.

class temp; 

dann einen Vektor zum Beispiel benannte Objekte mit Ihrer Klasse Art machen:

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

dann Sie eine Schleife zu Hinzufügen eines object.for Beispiels hinzufügen können, habe ich eine Klasse mit dem Namen Temp, der hat eine Funktion namens Eingang und ich möchte hinzufügen:

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

jetzt haben Sie eine dynamische Klasse. auf Ihre Objekte zugreifen, die Sie auf diese Weise verwenden können:

objects[i]; 

und wenn Sie ein Objekt löschen möchten, einfach auf diese Weise verwenden: 1.Suchen Ihr Objekt Lage im Vektor. 2.Ändern Menge des letzten Blocks des Vektors mit, dass und entfernen Sie den letzten Block:

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

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

wenn Sie den Speicherort des letzten Blocks des Vektors tun dies wissen wollen

Hinweis: Sie können Vektoren wie ein Array verwenden.

Verwandte Themen