2010-10-24 24 views
12

Załóżmy, że mam pudełko klasy , a użytkownik może utworzyć skrzynki . Jak to zrobić? Rozumiem, że tworzę obiekty przez className objectName(args);, ale jak to zrobić dynamicznie, w zależności od danych wejściowych użytkownika?Jak dynamicznie tworzyć obiekty klas?

+3

Czy możesz podać przykład kodu (potencjalnie pseudokodowego)? –

+0

Utwórz je w miejscu? Możesz na przykład przechowywać je w 'std :: vector', ale to naprawdę zależy od tego, co robisz. – GManNickG

+0

Niestety w języku C++ nie można dynamicznie wywoływać konstruktora. Jedynym sposobem jest przechowywanie obiektów, które są w stanie zwrócić świeżo skonstruowany obiekt tego, co chcesz w środowisku wykonawczym. Przykłady odpowiedzi, które już otrzymałeś, są całkowicie trafne. –

Odpowiedz

5

Poniższa metoda fabryka tworzy Box instancje dynamicznie w oparciu o dane wprowadzone przez użytkownika:

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

oczywiście PrettyBigBox i SmallBox zarówno wywodzących Box. Spójrz na schematy kreacji w C++ design patterns wikibook, ponieważ jeden z nich prawdopodobnie dotyczy Twojego problemu.

2

W C++ możliwe jest przydzielanie obiektów przy użyciu pamięci automatycznej (stos) i dynamicznej (sterty).

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. 

Można użyć wskazówki i sterty alokacji dynamicznie budować obiekty jak w:

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

Related: the "Factory" object-oriented design pattern

15

Prawidłowa odpowiedź zależy od wielu różnych klas, z których chcesz tworzyć instancje.

Jeśli liczba jest ogromna (aplikacja powinna być w stanie utworzyć wystąpienie dowolnej klasy w aplikacji), należy użyć funkcji odbicia .Net. Ale szczerze mówiąc, nie jestem wielkim fanem używania refleksji w logice biznesowej, więc radziłbym tego nie robić.

Myślę, że w rzeczywistości masz ograniczoną liczbę na zajęciach, dla których chcesz utworzyć instancje. I wszystkie inne odpowiedzi przyjmują to założenie. To, czego naprawdę potrzebujesz, to wzór fabryczny. W następnym kodem Zakładam również, że zajęcia z których chcesz utworzyć instancje, wszystkie wywodzą się z tej samej klasy bazowej, powiedzmy zwierząt, podobnie jak to:

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

Następnie utwórz abstrakcyjny fabryki, która jest interfejs, który tworzy zwierzę:

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

Następnie utwórz podklasy dla każdego z różnych gatunków zwierząt. Na przykład. dla klasy Dog stanie się to:

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

Tak samo dla kota.

Metoda DogFactory :: create zastępuje metodę IFactory :: create, nawet jeśli ich typ powrotu jest inny. To jest to, co nazywa się typami zwrotu co-variant. Jest to dozwolone, o ile typ zwracanej metody podklasy jest podklasą typu zwracanego klasy bazowej.

Co można teraz zrobić, to umieścić instancje tych wszystkich fabrykach w mapy, takich jak to:

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

Po wejściu użytkownika, trzeba znaleźć odpowiednie fabryki, i poprosić go, aby utworzyć instancję zwierzęcia:

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

Jest to typowe podejście do abstrakcyjnej fabryki. Istnieją również inne podejścia. Podczas uczenia się w C++ napisałem o tym mały artykuł CodeProject. Można go znaleźć tutaj: http://www.codeproject.com/KB/architecture/all_kinds_of_factories.aspx.

Powodzenia.

0

Prostym sposobem jest użycie wektora. najpierw umieść bibliotekę wektorową i utwórz tymczasowy obiekt jako swoją klasę.

class temp; 

następnie dokonać wektor na przykład o nazwie typu obiektów z klasy:

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

następnie można dodać pętlę do dodawania object.for przykład, mam klasę o nazwie temp, który ma funkcja o nazwie input i chcę dodać:

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

teraz masz klasę dynamiczną. , aby uzyskać dostęp do swoich obiektów można korzystać w ten sposób:

objects[i]; 

i jeśli chcesz usunąć obiekt, wystarczy użyć w ten sposób: 1.find swoją lokalizację obiektu w wektorze. ilość 2.change ostatniego bloku swojego wektora z tego i usunąć ostatni blok:

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

jeśli chcesz znać lokalizację ostatniego bloku swojego wektora zrobić:

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

uwaga: możesz używać wektorów takich jak tablica.

Powiązane problemy