2012-10-24 10 views
9

Jeśli mam klasę podstawową, tylko z metodami wirtualnymi i 2 klasami pochodnymi z klasy z klasą podstawową, z zaimplementowanymi tymi metodami wirtualnymi.Wskaźnik do tablicy klasy bazowej, zapełnij klasą pochodną

Jak to zrobić:

// causes C2259 
BaseClass* base = new BaseClass[2]; 

BaseClass[0] = new FirstDerivedClass; 
BaseClass[1] = new SecondDerivedClass; 

czyli

// causes "base is being used without being initialized" 
BaseClass* base; 
// causes CC59 again 
BaseClass* base = new BaseClass; 

base[0] = FirstDerivedClass(); 
base[1] = SecondDerivedClass(); 

(lub coś podobnego)

... tak, że można uzyskać dostęp do BaseClass s metod przez DerivedClass, ale przez wskaźnik i wskaźnik jest tablicą DerivedClass s?

Odpowiedz

8

macierzy jest niewłaściwego typu: przechowuje BaseClass obiektu wystąpień zamiast wskaźników do nich:. Ponieważ BaseClass wydaje się być abstrakcyjne, kompilator narzeka, że ​​nie może domyślnie skonstruować instancji, aby wypełnić tablicę.

Nawet jeśli nie były abstrakcyjne, użycie tablic polimorficznych to big no-no w C++, więc powinieneś robić wszystko inaczej w każdym przypadku.

Fix to przez zmianę kodu do:

BaseClass** base = new BaseClass*[2]; 

BaseClass[0] = new FirstDerivedClass; 
BaseClass[1] = new SecondDerivedClass; 

powiedział, że przez większość czasu to korzystne jest stosowanie std::vector zamiast zwykłych tablic i inteligentnych wskaźników (takich jak std::shared_ptr) zamiast głupich wskaźników. Korzystanie z tych narzędzi zamiast ręcznego pisania kodu zadba o przejrzystość wielu problemów przy wyjątkowo małym koszcie runtime.

+1

Problem, który jest nazywany "krojeniem obiektów", nie jest charakterystyczny dla tablic - zdarza się za każdym razem, gdy przypisujesz klasę pochodną do klasy bazowej * według wartości *. Na przykład. 'BaseClass b; b = FirstDerivedClass(); 'jest kompilowanym C++, który jednak łamie się cicho (w najlepszym wypadku może pojawić się ostrzeżenie kompilatora). –

+0

Link wydaje się być przeniesiony. – user6003859

+1

@ user6003859 Zaktualizowałem, dzięki za spekulacje! – Jon

3

Jest C++ używać std::vector zamiast prostego tablicy:

std::vector<BaseClass*> base; 
base.push_back(new FirstDerivedClass()); 
base.push_back(new SecondDerivedClass()); 

Jak Kerrek SB zauważył najbezpieczniejszą metodą jest użycie std::unique_ptr:

std::vector<std::unique_ptr<BaseClass> > base; 
base.push_back(std_unique_ptr<BaseClass>(new FirstDerivedClass())); 
base.push_back(std_unique_ptr<BaseClass>(new SecondDerivedClass())); 
+2

Ale jeśli chcę tablicy? – Deukalion

+1

Po co? Prędkość? Niezawodność? –

+0

Co ze: BaseClass * Base [2]; Base [0] = new FirstDerivedClass; Base [1] = new SecondDerivedClass; – Al2O3

2

Jeśli zawiera klasy bazowej czystych metod wirtualnych, to nie uda się skompilować:

BaseClass* base = new BaseClass[2]; 

Jeśli nie, masz zamiar dostać wyciek pamięci.

W języku C++ odbywa się to za pomocą std :: vector lub std :: array, z pewnym inteligentnym wskaźnikiem. Np

std::vector< std::shared_ptr<BaseClass> > arr(2); 
arr[0].reset(new FirstDerivedClass()); 
arr[1].reset(new SecondDerivedClass()); 
+0

Jeszcze ważniejszym problemem z kodem OP jest * krojenie obiektów *, które cicho łamie programy. –

+0

@j_random_hacker Dlatego zaproponowałem użycie jakiegoś inteligentnego wskaźnika. Przechowywanie obiektów typu podstawowego (jeśli nie ma żadnych czystych funkcji) spowodowałoby krojenie –

0

To odpowiedź (od Rubby)

BaseClass* Base[2]; 

Base[0] = new FirstDerivedClass; 
Base[1] = new SecondDerivedClass; 
+1

To coś * bardzo * różni się od tego, co próbował twój pierwotny kod. Ta tablica jest przydzielana na stosie, podczas gdy pierwotnie znajdowała się na stercie. – Jon

+0

Tak, myślę. Teraz tablica jest wskaźnikiem i są wskaźniki w tablicy. – Deukalion

0

zdefiniować tablicy wskaźnik, typu wskaźnika jest klasy bazowej. I przypisz wskaźnik do klasy pochodnej do elementów tablicy. Po prostu:

BaseClass* base [2]; 
base[0] = new FirstDerivedClass; 
base[1] = new SecondDerivedClass; 
Powiązane problemy