jak mozna przy dziedziczeniu klasy w c++ zrobic taki myk ze: "A" dziedziczy po "B"
i zamiast tego
((B*)A)->xoxo();
to zrobic tak A->asB()->xoxo() ?
jak mozna przy dziedziczeniu klasy w c++ zrobic taki myk ze: "A" dziedziczy po "B"
i zamiast tego
((B*)A)->xoxo();
to zrobic tak A->asB()->xoxo() ?
A->B::xoxo();
class B
{
public:
A* asA(){return (A*)this;}
}
class A: public B
{
void xoxo1();
void xoxo2();
}
Chce osiągnąc coś takiego, czy jest to możliwe? Bo ja twierdze że nie, ale jako że nie jestem zbyt inteligentny pytam się mądrzejszych.
Jeśli to 'to' sprowadza się do kwestii związanych z kompilacją, to da się to zrobić - daj deklarację zapowiadającą klasy A przed definicją B. Problem w tym, że taka konstrukcja jest mało bezpieczna i użyteczna, ponieważ klasa B nie jest klasą A, więc wywołanie metody asA będzie poprawne tylko dla klasy A i jej pochodnych, wszystkie inne wywołania będą błędne.
To jest jakiś hardkor co chcesz zrobić. To jest coś takiego:
Mamy klasę Zwierze i klasę Człowiek która z niej dziedziczy. Ty chcesz umozliwić obiektowi Zwierze udawać Człowieka (rzutowanie B na A). Zauważ ze Zwierze NIE MA takich umiejętności (metod) jak Człowiek. Próba odwołania się do nich spowoduje najpewniej wysypanie się programu, bo nie będzie dostępu do pól Człowieka z których metody będą chciały korzystać.
Samo wywołanie metod będzie działać, o ile nie będą to metody wirtualne, ale tak się po prostu nie robi ;]
@down miałem zaćmienie lekkie ;)
Shalom napisał(a)
Nie wiem czy zdajesz sobie sprawę z tego że każdy obiekt przechowuje w sobie informacje o swoich metodach.
A to od kiedy?
Próba odwołania się do nich spowoduje najpewniej wysypanie się programu, bo nie będzie dostępu do pól Człowieka z których metody będą chciały korzystać.
Niby dlaczego cokolwiek miałoby się wysypać? Pola są rozłożone w pamięci po kolei, więc jeżeli obiekt faktycznie został utworzony jako docelowy typ, to nie powinno być żadnego problemu.
ale najpierw trzeba wiedzieć, że to jest typ docelowy! W tym kodzie brakuje właśnie sprawdzenia czy konwersja jest możliwa.
Owszem takie sztuczki są robione w profesjonalnym kodzie, ale zawsze jest wbudowany lub udostępniony mechanizm weryfikacji typu (niekoniecznie oparty na RTTI).
class A; // pewnie tego Ci zabraklo. kompilator w linii "X" musi znac nazwę "A" i *wiedziec* czym ona będzie!
class B
{
public:
A* asA(){return (A*)this;} // linia X
};
class A: public B
{
void xoxo1();
void xoxo2();
};
btw1.
A* asA(){return (A*)this;}
powinno byc raczej parą i uzywac referencji, bo nigdy te wskazniki nie sa zerowe (obiekt B istnieje, prawda?):
A& asA() {return (A)this;}
A const & asA() const {return (A)this;}
btw2.
oczywiscie kod sie bedzie kompilowal, ale to nie znaczy ze takie podejscie jest ok.. jesli wprowadzisz wiecej klas dziedziczacych po Be, bedziesz mial sporo zabawy i upierdliwosci w pilnowaniu ze to-Be jest faktycznie tamtym-Aa a nie jakims-Ce
btw3.
jezeli kompilator Ci krzyczy errorami lub warningami ze nie da sie lub ze niebezpiecznie jest rzutowac z B na A, uzyj reinterpret_cast<A*>(this) lub dynamic_cast jezeli dodatkowo chcialbys miec runtimeowa kontrole poprawnosci typow (acz wtedy klasy te musza miec w sobie cokolwiek 'virtual')
W zasadzie dynamic_cast to jest chyba to o o chodzi... Mam rację?