Odniesienie się do funkcji klasy dziedziczonej

0

Witam,

W programie posiadam kontener vector na wskaźniki do klasy abstrakcyjnej od ktorej dziedzicza potem kolejne klasy:

vector<Kl_abstrakcyjna * > Vec;
 

Nastepnie Vec jest zapelnianiany wieloma elementami:

Vec.push_back(new Obiekt_dziedziczony1());
Vec.push_back(new Obiekt_dziedziczony2());
Vec.push_back(new Obiekt_dziedziczony3());
Vec.push_back(new Obiekt_dziedziczony4());
 

itd.

Oczywiscie Obiekt_dziedziczony dziedziczy po klasie abstrakcyjnej Kl_abstrakcyjna.

Mam pytanie w jaki sposób mogę wywołać taka funkcje, która istnieje dodatkowo tylko w Obiekt_dziedziczony3 uzywajac takiej skladni:

for(int i=0;i<Vec.size();i++)
{
if(.....) //jesli Vec[i] jest Obiektem dziedziczonym3 wywolaj funkcje, ktora istnieje tylko w Obiekt_dziedziczony3
Vec[i]->uruchom_funkcje_w_obiekt_dziedziczony3();

}


Dzieki za pomoc

2

Nie idz ta droga.

0

Nie najlepszy design, ale jeśli koniecznie chcesz to zrobić to:

Obiekt_dziedziczony3* foo = dynamic_cast<Obiekt_dziedziczony3*>(Vec[i]);
if (foo)
{
    foo->uruchom();
}
3
struct A{
	virtual ~A(){}
};

struct B : A{
};

struct C : A{
};

Jeśli wiesz na pewno, że to obiekt tego typu - użyj static_cast.

A* ab = new B;

B* bb = static_cast<B*>(ab); // OK
C* cc = static_cast<C*>(ab); // dereferencja tego wskaźnika to UB

Jeśli chcesz sprawdzić - użyj dynamic_cast.

A* ab = new B;

B* bb = dynamic_cast<B*>(ab); // OK
C* cc = dynamic_cast<C*>(ab); // cc == nullptr

Możesz też po prostu utworzyć interfejs z funkcjami wirtualnymi.

Co do Twojego kodu:

  • używanie nagiego new i delete to antyidiom w C++
  • używaj inteligentnych wskaźników zamiast nagich, jeśli chcesz kontrolować za ich pomocą czas życia obiektów, na które wskazują
  • mam nadzieję, że nazwy funkcji i obiektów nadałeś wyłącznie na cel przykładu.
0

Dzieki za odpowiedź ;)

@kq
W moim programie oczywiscie nie mam tak nazwanych obiektów i funkcji ;)

Mam pewny problem, gdyż tak wygląda moj kontener w rzeczywistosci i nie jest tylko zwykłym wskaźnikiem:

std::vector<std::shared_ptr <Obiekt> > * obiekty;
 

Obiekt to klasa podstawowa i abstrakcyjna.

W jaki sposób sprawdzić czy w tym obiekcie znajduje się klasa Bomba, która dziedziczy publicznie po klasie Obiekt.

Robiąc to w ten sposób:

std::shared_ptr <Bomba> bomba_wsk = dynamic_cast< std::shared_ptr<Bomba> >(obiekty[i]);

Wyrzuca błąd. Wydaje mi się, że jest to spowodowane tym, że vector 'obiekty' jest wskaźnikiem.
Musiałem uczynić z niego wskaźnik, gdyż wcześniej w konstruktorze klasy w której znajduje się ten kontener przekazuje w nim referencje do 'rzeczywistego' kontenera z innej klasy, tak abym miał możliwość jego edycji z drugiej klasy. Troche to pogmatwane, ale mam nadzieję że zrozumieliście. Zresztą nie jest to aż tak ważne w tym temacie;)

Macie jakiś pomysł jak to sprawdzić konkretnie na moim rzeczywistym przykładzie?

Dzięki

2

(*obiekty)[i] lub obiekty->at(i) (at ma ciut inne zachowanie - rzuca wyjątek jak i nie jest w zakresie [0, wielkość wektora], zamiast powodować UB.

shared_ptr castuj za pomocą std::dynamic_pointer_cast (lub innych analogicznych http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast ) , ale lepiej, żeby Twój Obiekt był interfejsem z metodą wirtualną!

std::shared_ptr <Bomba> bomba_wsk = std::dynamic_pointer_cast<Bomba>(obiekty->at(i));
0

Nie rozumiem sensu tworzenia wskaźnika na vector... nie lepiej działać na referencjach ?

0

@kq

Nie jestem aż tak obcykany w tym temacie, ale co masz na mysli mówiąc o interfejsie?

1
Tropican1 napisał(a):

@kq

Nie jestem aż tak obcykany w tym temacie, ale co masz na mysli mówiąc o interfejsie?

Klasa bazowa deklaruje jakie ma funkcje, a klasy dziedziczące je implementują. Dzięki metodom wirtualnym nie musisz wiedzieć na jakim dokładnie typie operujesz.

W uproszczeniu:

struct Bron{
    virtual void atak()=0;
};

struct Karabin : Bron{
    void atak() override { cout << "strzela" << endl; }
};

struct Bomba: Bron{
    void atak() override { cout << "BOOM" << endl; }
};

Teraz mając vector<smart_ptr<Bron>> możesz na każdym elemencie wywołać ->atak() i zostanie wywołana odpowiednia funkcja.

1 użytkowników online, w tym zalogowanych: 0, gości: 1