rzutowanie w dół

0

Cześć :)

class Base {
public:
    virtual Base* clone() const
    {
        return new Base(this);
    }
};

class Derived : public Base {
public:
    virtual Base* clone() const
    {
        return new Derived(this);
    }
};

Z tego kodu wynika, że tu zajdzie rzutowanie w dół. Tylko ja nie rozumiem, czy można tu rzutować w dół. Bo niby dlaczego można zrobić to bezpiecznie. W thinkingu in C++ jest odradzane rzutowanie w dół. Wreszcie, kiedy można bezpiecznie rzutować w dół?
Pozdrawiam! :D

2

W dół zawsze jest bezpiecznie, skoro jesteś człowiekiem to na 100% jesteś też ssakiem. Jedynym niebezpieczeństwem może być wyciek pamięci związany z brakiem wirtualnego destruktora.

0

w górę też jest bezpieczne, co nie?
Jeżeli w dół jest zawsze bezpieczne to po co dynamic_cast?

1

Każdy człowiek jest ssakiem ale nie każdy ssak jest człowiekiem, więc w górę trzeba koniecznie sprawdzać, w razie pomyłki łatwo o mazanie po pamięci.

0

Dobrze, ale przecież polimorfizm opiera się na rzutowaniu w górę i tu nigdy się nie martwimy o bezpieczeństwo

2

Odwrotnie. W gore jest bezpiecznie, w dol niekoniecznie.

  • Przy cloneach, typem zwracanym jest wskaznik do konkretnej klasy, a nie bazowej.
0
  • Przy cloneach, typem zwracanym jest wskaznik do konkretnej klasy, a nie bazowej.

No właśnie o to chodzi, że nie ;). Jak tak zwrócisz, to w jaki sposób dojdzie do przesłonienia, skoro funkcje będą miały inne sygnatury?

0

dobrze, no to w końcu jak to jest z tymi rzutowaniami, które są bezpieczne, a które nie ?

1

Rzutowac w gore mozna za darmo. Do rzutowania w dol trzeba uzyc static_cast<>/dynamic_cast<>.

2

Rzutowanie typu pochodnego na bazowy jest bezpieczne (zgodnie z liskov substitution principle). W druga stronę niekoniecznie.

0

Odnosząc się do tego:
http://www.parashift.com/c++-faq/virtual-ctors.html
Może mi ktoś wyjaśnić jak to działa? Jest to dla mnie pewne novum. Zawsze się mówiło:
żeby można było przesłonić metodę musi mieć taką samą sygnaturę, bo niby skąd kompilator ma wiedzieć, o którą metodę chodzi. No właśnie, skąd ma wiedzieć? Jak wyjaśnić ten mechanizm?
Co w takiej sytuacji się dzieje? Następuje rzutowanie czy jak?

1

Może mi ktoś wyjaśnić jak to działa? Jest to dla mnie pewne novum. Zawsze się mówiło:
żeby można było przesłonić metodę musi mieć taką samą sygnaturę, bo niby skąd kompilator ma wiedzieć, o którą metodę chodzi. No właśnie, skąd ma wiedzieć? Jak wyjaśnić ten mechanizm?

Zależy co do tej sygnatury należy. Zwracany typ chyba nie należy?
http://stackoverflow.com/questions/290038/is-the-return-type-part-of-the-function-signature

0

Dobrze. Rozumiem. Typy są kowariantne, czyli po prostu typ podrzędny jest typu nadrzędnego.
Ale teraz jeżeli w takim o to kodzie:

#include <iostream>
using namespace std;

class Base {
public:

    virtual Base* clone() {

        return new Base(*this);
    }

    void show() {
        cout << "BASE\n";

    }
};

class D1 : public Base {
public:
    D1* clone() {

        return new D1(*this);
    }

    void show() {
        cout << "D1\n";
    }

};



int main(int argc, char** argv) {
    D1 d1;
      Base& ptr1 = d1;
    (*(ptr1.clone())).show();

    return 0;
}

Mamy właśnie wywołanie klonowania na referencji typu Base wskazującej na obiekt typu D1. Ponieważ ta funkcjia jest wirtualna, a w pochodnej mamy przesłonięcie "koowariantne" to wywoała się metoda z klasy pochodnej. Co w takim razie zostanie zwrócone tu ptr1.clone()? Wskaźnik do Base czy wskaźnik do pochodnej? Dlaczego?
Z góry dziękuję :)

1

Zmień void show() na virtual i kod sam we wszystkim się przyzna.

0

to robiłem. Czyli rozumiem, że zwracacny jest WSKAŹNIK typu Base, a wskazuje a obiekt typu D1?

1

Nie, wywoływane jest D1* clone() { ale metody które nie są wirtualne nie przyjmują się metodami wirtualnymi.
Widać że ptr1 jest typu base, widać że metoda clone w base zwraca base* więc kompilator "logicznie wnioskuje" że trzeba wywołać base::show.

2

Spytaj kompilator. http://ideone.com/kC93w8

0

No ale przecież jeżeli mamy metodę virutalną show to już wywoływana jest metoda D1.

no ale czy typeid() nie patrzy tylko po typie obiektu? Mnie interesuje jakiego jest typu wskaźnik i na co wskazuje.

1

no ale czy typeid() nie patrzy tylko po typie obiektu? Mnie interesuje jakiego jest typu wskaźnik i na co wskazuje.

Tu http://4programmers.net/Forum/C_i_C++/235149-rzutowanie_w_dol?p=1042160#id1042160 masz odpowiedź na oba pytania, mów którego słowa nie rozumiesz.\

no ale czy typeid() nie patrzy tylko po typie obiektu? Mnie interesuje jakiego jest typu wskaźnik i na co wskazuje.

Człowieku czasami rusz trochę głową i zrób test w kodzie:

D1 d1;
Base *ptr1=&d1;
cout<<typed(ptr1).name()<<endl;
cout<<typed(*ptr1).name()<<endl;

zauważ że masz w tym przypadku mniej pisania niż napisałeś w poście, a i odpowiedź dostajesz szybciej.

0

skoro takie to wszystko oczywiste to wyjaśnij takie zachowanie:
Zakładamy, że metoda show() nie jest wirtualna.

cout<<typed(ptr1).name()<<endl;
cout<<typed(*ptr1).name()<<endl;

Według tego co napisałeś *ptr1 jest obiektem typu D1. A skoro jest obiektem takiego typu to możemy sobie wywołać JEGO funkcję składową. No to do dzieła:
(*ptr1).show().
Outputem jest BASE. Dlaczego, skoro przecież naszym *ptr1 jest obiektem typu D1?

0

Tylko wirtualne metody patrzą na to jakiego typu naprawdę jest obiekt.
Natomiast dla metody nie wirtualnej z tego Base *ptr1 jednoznacznie wynika że jest typu Base.

0

No ale poczekaj. Kazałeś się przekonać w ten sposób:

cout<<typed(*ptr1).name()<<endl;

I wg tego obiekt jest D1, czyżby typeid() było zawodne w tym przypadku?

1

Powiedz mi jakiego słowa nie rozumiesz w zdaniu: "funkcje nie wirtualne nie uwzględniają wirtualności"
funkcje wirtualne widzą to: cout<<typed(*ptr1).name()<<endl;
zaś funkcje nie wirtualne widzą tylko to: cout<<typed(ptr1).name()<<endl;

0

Ale Ty ciągle nie odpowiadasz na pytanie.

0

Na jakie pytanie?

1

no ale czy typeid() nie patrzy tylko po typie obiektu? Mnie interesuje jakiego jest typu wskaźnik i na co wskazuje.

Najpierw dowiadujemy sie czym jest wskaznik, potem sie zajmuje tym, jak dziala polimorfizm. Inaczej sie krotko mowiac nie da, czego przykladem jest ten watek.

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