2014-10-06 16 views
7

Próbuję zrobić wektor w C++, który może przechowywać 3 różne typy danych. Nie chcę używać biblioteki boost. Coś jak:Wektor, który może mieć 3 różne typy danych C++

vector<type1, type2, type3> vectorName; 

Czy muszę wykonać szablon? A jeśli tak, to jak mam to zrobić?

+0

Prawdopodobnie potrzebny byłby pewien typ klasy/kontenera otoki do przechowywania odniesień do różnych typów. Podobne pytanie [tutaj] (http://stackoverflow.com/questions/13461869/c-push-multiple-types-onto-vector) – Abbath

+0

Zobacz ['tuple'] (http://www.cplusplus.com/reference/tuple /), być może. Wektory (aka list) są sekwencjami jednego lub więcej * homogenicznych * przedmiotów. Krotki to skończone (i o ustalonej wielkości) zbiory możliwych heterogenicznych członków. – user2864740

+2

Czy chcesz mieć wektor, którego elementy zawierają wszystkie 3 typy? Lub wektor, który może zawierać jeden typ lub inne? – Galik

Odpowiedz

6

Najprostszym sposobem przechowywania wielu typów w tym samym wektorze jest nadanie im podtypów klasy nadrzędnej, zawijanie żądanych typów w klasy, o ile nie są już klasami.

class Parent 
{ 
    //anything common to the types should be declared here, for instance: 
    void print() //make this virtual if you want subclasses to override it 
    { 
    std::cout << "Printing!"; 
    } 

    virtual ~Parent(); //virtual destructor to ensure our subclasses are correctly deallocated 
}; 

class Type1 : public Parent 
{ 
    void type1method(); 
}; 

class Type2 : public Parent 
{ 
    void type2Method(); 
}; 


class Type3 : public Parent 
{ 
    void type3Method(); 
}; 

Następnie można utworzyć wektor Parent wskaźników, które mogą przechowywać wskaźniki do typów dziecko:

std::vector<Parent*> vec; 

vec.push_back(new Type1); 
vec.push_back(new Type2); 
vec.push_back(new Type3); 

Podczas uzyskiwania dostępu do elementów bezpośrednio z wektora, będziesz mógł korzystać tylko członkom, że należą do Parent. Na przykład, można napisać:

vec[0]->print(); 

lecz nie:

vec[0]->type1Method(); 

jako typ element został zadeklarowany jako Parent* oraz typ Parent ma type1Method.

Jeśli chcesz uzyskać dostęp do członków podtypów specyficzny, można konwertować Parent wskaźniki do podtypu wskazówek tak:

Parent *p = vec[0]; 

Type1 *t1 = nullptr; 
Type2 *t2 = nullptr; 
Type3 *t3 = nullptr; 

if (t1 = dynamic_cast<Type1*>(p)) 
{ 
    t1->type1Method(); 
} 
else if (t2 = dynamic_cast<Type2*>(p)) 
{ 
    t2->type2Method(); 
} 
else if (t3 = dynamic_cast<Type3*>(p)) 
{ 
    t3->type3Method(); 
} 

Mimo to powszechnie uważany za lepszy pomysł, aby uniknąć tego rodzaju wyraźnej typu rozgałęzienia i zamiast tego polegać na metodach wirtualnych.

Pamiętaj, aby usunąć wskaźniki przed usunięciem ich z wektora, jeśli używasz alokacji dynamicznej, tak jak to zrobiłem w powyższym przykładzie. Alternatywnie, użyj inteligentne kursory (prawdopodobnie std::unique_ptr i niech pamięć dbać o siebie:

std::vector<std::unique_ptr<Parent>> vec; 
+0

Nic nie usunąłeś. Dlaczego nie użyć wektora unique_ptr, więc automatycznie usuwa go? Rodzic potrzebuje wirtualnego destruktora. –

+0

@NeilKirk W prawo, zapomniałem o wirtualnym destruktorze. Wspomnę też o inteligentnych wskaźnikach. – ApproachingDarknessFish

+0

Ok Mogę dodać różne typy do mojego wektora, ale nie mogę uzyskać dostępu do konkretnych metod w typach. Jak mogę uzyskać dostęp do tych różnych metod? Na przykład, jeśli chcę wywołać vec [i] .print(); Dzięki za pomoc! –

5

Próbuję dokonać wektor w C++, które można przechowywać 3 różne typy danych.

Odpowiedź tutaj naprawdę zależy od konkretnego przypadku użycia:

  1. Jeśli obiekty są w jakiś sposób związane i podobny w pewien sposób - stworzyć klasę bazową i czerpać wszystkie klasy z nią, a następnie dokonać sklep wektor unique_ptr s do klasy nadrzędnej (patrz ApproachingDarknessFish s odpowiedź szczegóły),

  2. Jeśli obiekty są wszystkie podstawowe (tak wbudowane) typy - używać union że grupy rodzaje i zdefiniować vector<yourUnionType>,

  3. Jeśli obiekty są nieznanego typu, ale jesteś pewna, że ​​dzielić similiar interfejs utworzyć klasę bazową i czerpać szablonie klasy dziecko od niego (template <typename T> class container: public parent{};) i stworzyć vector<unique_ptr<parent>> jak w pierwszym przypadku,

  4. Jeśli obiekty są typy, które z jakiegoś powodu nie mogą być podłączone (tak na przykład vector sklepy int, std::string i yourType), połączyć je poprzez union, jak w . Lub - jeszcze lepiej ...

... jeśli masz czas i chcesz się czegoś nauczyć - wyglądają jak boost::any jest realizowany i spróbuj wdrożenie go samodzielnie, jeśli naprawdę nie chcesz użyć samej biblioteki . To nie jest tak trudne, jak mogłoby się wydawać.

+0

Dlaczego ograniczenie w opcji 2? – MSalters

+0

@MSalters, ponieważ mocno wierzę, że jeśli tak nie jest - pozyskanie klasy bazowej jest bardziej zorientowane obiektowo. Ponadto - używanie związków w "wektorze" nie jest szczególnie wygodne - musisz dodatkowo przechowywać wektor wtórny, który zawierałby typ, który przechowuje każda Unia, abyś miał do niego odpowiedni dostęp i nie dostawał śmieci. –

+0

Potrzeba wektora dyskryminacji jest potrzebna również dla podstawowych typów, więc nie ma powodu, aby robić rozróżnienie. A jak zauważysz, brak wspólnej klasy bazowej jest prawdziwym problemem, więc dlaczego nie trzymać się opcji 2 w tym przypadku zamiast brzydkiego hackowania w 4? – MSalters