Rzutowanie w górę i dół hierarchii

0

Cześć,
Wątek zakładam, ponieważ chcę zrozumieć po co tak naprawdę jest rzutowanie w górę i w dół hierarchii

Wiem następujące rzeczy:

  1. Aby rzutowanie można było wykonać to obiekty muszą dziedziczyć po jednej klasie bazowej (najprostszy przypadek),
  2. Rzutowanie służy po to aby móc się dobrać do metod klasy bazowej lub pochodnej - tj w zależności w którą stronę hierarchii wykonujemy rzutowanie,
  3. Klasy muszą zawierać metody wirtualne - dotyczy to rzutowania wskaźników metodą dynamic_cast, natomiast static_cast obiekty muszą być statyczne tj. nie mogą to być wskaźniki
  4. Prawda jest taka, że rzutowanie nie zmienia typu obiektu i jego właściwości, jest to tak jakby inna etykieta obiektu - coś w rodzaju referencji ?

Sugerowałem się następującymi wątkami rzutowanie w górę i w dół oraz tym tematem

W odpowiedziach chciałbym się dowiedzieć następujących rzeczy:

  1. gdy wykonuję rzutowanie, to w jaki sposób można się dobrać do metod klasy bazowej lub pochodnej ? - w zależności od kierunku rzutowania - Prosiłbym o przykłady
  2. Czemu rzutowanie ma służyć ? Prosiłbym o jakieś przykłady i wyjaśnienie
  3. Zrobiłem sobie taki przykład:
#include <iostream>
#include <string>
using namespace std;

class osoba{
public:
    osoba(void){_imie="pusty"; _nazwisko="pusty";}
    osoba(string imie, string nazwisko):_imie(imie), _nazwisko(nazwisko){}

    inline void pokaz(void){
        std::cout << _imie << " " << _nazwisko << std::endl;
    }

    string _imie;
    string _nazwisko;
};

class menedzer : public osoba{
public:
    menedzer(string imie, string nazwisko):osoba(imie, nazwisko){}
};

class robol : public osoba{
public:
    robol(string imie, string nazwisko, menedzer *szef):osoba(imie,nazwisko){
        _szef=szef;
    }
    menedzer *_szef;

    menedzer *ktoJestSzefemRobola(){
        return _szef;
    }
};

void premia(osoba &os){
    std::cout << "Gratulacje !!! dostajesz premie !!! -> ";
    os.pokaz();
}

int main(void)
{
    menedzer m("jajcarz","fajny");
    robol r("silny","twardziel",&m);

//    std::cout << r.ktoJestSzefemRobola()->_nazwisko;

    std::cout << std::endl;

    osoba o("xx","zz");

//    r = static_cast<robol&>(o); // <- odkomentuj ten kawałek i skompiluj
//    std::cout << "dane robola - ";
//    r.pokaz();

    o = static_cast<osoba&>(r);
    std::cout << "dane osoby - ";
    o.pokaz();

//    std::cout << "dane robola - " << r._imie << " " << r._nazwisko;

//    std::cout << std::endl;

//    premia(r);

    std::cout << std::endl;

    return 0;
}

W powyższym przykładzie wystarczy odkomentować jedną linię która jest opisana komentarzem i pokazuje istotę rzutowania ale nie wiem:

  1. czy ten przykład jest prawidłowy ?,
  2. jakie wnioski z niego wyciągnąć ?

Czemu drążę temat rzutowania ? Bo chcę zrozumieć, czemu to używać, po co i w jakich sytuacjach ? Ponieważ w Qt robią takie rzutowanie i nie wiem dlaczego...

void MyDateEditDelegateCol5Tab0::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QDate value = index.model()->data(index, Qt::EditRole).toDate().currentDate();

    QDateEdit *DateEdit = static_cast<QDateEdit *>(editor);
    DateEdit->setDate(value);
}

Będę wdzięczny za pomoc w zrozumieniu tematu

0

Tutaj Znajdziesz wszystko, rozdziały chyba 11i 12:
https://www.learncpp.com/cpp-tutorial/111-introduction-to-inheritance/

0
zkubinski napisał(a):

Czemu drążę temat rzutowania ? Bo chcę zrozumieć, czemu to używać, po co i w jakich sytuacjach ? Ponieważ w Qt robią takie rzutowanie i nie wiem dlaczego...

void MyDateEditDelegateCol5Tab0::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QDate value = index.model()->data(index, Qt::EditRole).toDate().currentDate();

    QDateEdit *DateEdit = static_cast<QDateEdit *>(editor);
    DateEdit->setDate(value);
}

Musisz rzutować, bo QWidget nie posiada metody setDate. QDateEdit ma tę metodę, a przy okazji dziedziczy pośrednio po QWidget, więc istnieje szansa, że argument editor wskazuje "pod spodem" na instancję QDateEdit. Ale to nie jest pewnik, więc powinieneś to sprawdzić.

W przypadku Qt masz do dyspozycji qobject_cast i jeśli operujesz na klasach dziedziczących po QObject to powinieneś zamiast static_cast używać właśnie qobject_cast, bo :

  • jest bezpieczniejsze, w przypadku błędnego typu zwraca nullptr.
  • jest "lżejsze" niż dynamic_cast, nie wymaga RTTI.

Przy okazji polecam obejrzeć CppCon2019 Jon Kalb: Back to Basics: Object-Oriented Programming"

0
zkubinski napisał(a):

metoda setDate dostępna jest w klasie QDate w dokumentacji nie ma nic o dziedziczeniu, dla pewności zrobiłem sobie taki oto kod:

QDateEdit *DateEdit; 
DateEdit = new QDateEdit(); 
DateEdit->setDate(QDate::currentDate()); 

QDate nie dziedziczy po niczym, nawet po QWidget. Nawet robiłem sobie przykłady z rzutowaniem aby uzyskać dostęp do metod i o dziwo wychodzi mi, że rzutowanie jest bez sensu, bo do metod można i tak się dobrać z racji dziedziczenia...

Wszystko fajnie, ale w ten sposób tworzysz nowy obiekt klasy QDateEdit, a metoda setEditorData przesyła Ci jako jeden z argumentów wskaźnik na już istniejący obiekt, który został stworzony wcześniej gdzieś indziej. Na tym obiekcie musisz operować jeśli chcesz, żeby jakiekolwiek zmiany miały efekt.

void MyDateEditDelegateCol5Tab0::setEditorData(QWidget *editor, const QModelIndex &index) const

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