• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Dziedziczenie protected a konwersja referencji klasy pochodnej na klasę podstawową.

0 głosów
71 wizyt
pytanie zadane 12 lutego w C i C++ przez SQnera Początkujący (260 p.)
Witam

Mam pytanie. Dlaczego tylko przy dziedziczeniu w sposób publiczny możliwe są konwersje standardowe referencja/wskaźnik klasy pochodnej na referencja/wskaźnik klasy podstawowej. Czy możliwe jest żeby to jakoś obejść np deklaracją przyjaźni czy dynamic_cast?
komentarz 13 lutego przez Patrycjerz Mędrzec (159,770 p.)
Podaj przykładowy kod.

2 odpowiedzi

+1 głos
odpowiedź 13 lutego przez j23 Nałogowiec (46,860 p.)

Dlaczego tylko przy dziedziczeniu w sposób publiczny możliwe są konwersje standardowe referencja/wskaźnik klasy pochodnej na referencja/wskaźnik klasy podstawowej.

Jeśli jakaś klasa jest dziedziczona prywatnie, to znaczy, że jej interfejs ma być niewidoczny na zewnątrz. Dlatego nie jest możliwa niejawna konwersja pochodna -> bazowa (ukryta). Obejść to możesz dając reinterpret_cast, ale IMO to łamanie reguły dostępu.

komentarz 13 lutego przez monika90 Gaduła (3,200 p.)
edycja 13 lutego przez monika90
reinterpret_cast może dać nieprawidłowy wynik w niektórych sytuacjach, więc do konwersji do niedostępnej klasy podstawowej lepiej użyć rzutowania w stylu C. Oczywiście, najlepiej w ogóle tego nie robić.
komentarz 13 lutego przez j23 Nałogowiec (46,860 p.)

W sumie racja, przy wielodziedziczeniu reinterpret_cast  może dać nieprawidłowy adres.

komentarz 14 lutego przez Piotr Batko Gaduła (4,250 p.)

@monika90 i @j23

Czy w tej sytuacji rzutowanie dynamic_cast zadziałałoby poprawnie? Jeżeli tak, to dlaczego zalecacie stosowanie rzutowania z języka C?

1
komentarz 14 lutego przez j23 Nałogowiec (46,860 p.)

Najprościej sprawdzić samemu ;)

 

dynamic_cast, jak i static_cast, nie przepuści takiego rzutowania z powodu, o którym pisałem wcześniej.

 

komentarz 14 lutego przez Piotr Batko Gaduła (4,250 p.)

Racja. Sprawdziłem, faktycznie nie działa. A wiecie może co robi pod spodem to magiczne rzutowanie z C w tej sytuacji? Ja myślałem, że rzutowanie w stylu C daje się całkowicie zastąpić tymi z C++, ale skoro static i dynamic nie dadzą z tym rady, a reinterpret może dać nieprawidłowy wynik w niektórych sytuacjach, to jednak się myliłem.

komentarz 14 lutego przez j23 Nałogowiec (46,860 p.)

ale skoro static i dynamic nie dadzą z tym rady

Nie chodzi o to, że nie dadzą z tym rady, tylko one nie pozwalają na rzutowania, które łamią pewne zasady, a tu ewidentnie masz z tym do czynienia. Rzutowanie C działa, bo kompilator jest mniej restrykcyjny w stosunku do tego typu rzutowań. Zamiast klasy pochodnej możesz dać inną klasę, niezwiązaną z bazową, i też przejdzie. Po to wprowadzono *_cast, żeby zawczasu wykryć tego typu podejrzane rzutowania.

komentarz 14 lutego przez Piotr Batko Gaduła (4,250 p.)

Jaka jest różnica pomiędzy użyciem reinterpret_cast, a rzutowania w stylu C w tym konkretnym przypadku? Ty i Monika90 napisaliście o tym, że mogą czasami (Ty dopisałeś, że przy wielodziedziczeniu) zachowywać się inaczej. Czy mógłbyś napisać kod który by to obrazował? Ja jestem przekonany, że zadziałają tak samo - nie zmieniając adresu obiektu do którego się odnosimy, zmienią typ referencji/wskaźnika.

#include <iostream>

class Base1 {};
class Base2 {};
class Derived: private Base1, private Base2 {};

int main()
{
	Derived d;
	Base1 & cppStyle = reinterpret_cast <Base1 &> (d);
	Base1 & cStyle = (Base1 &) d;

	std::cout << (&cppStyle == &cStyle) << std::endl;

	return 0;
}

W kodzie powyżej zastosowałem wielodziedziczenie. Skoro referencje odnoszą się do obiektów o tych samych adresach i obie mają takie same typy, to rzutowania zachowały się identycznie (program drukuje 1, więc tak jest w tym przypadku).

1
komentarz 15 lutego przez j23 Nałogowiec (46,860 p.)

Try this:

class Base1 { char tab[10] = { 0 }; };
class Base2 { int v; };
class Derived: private Base1, private Base2 {};
 
int main()
{
    Derived d;
    Base2 & cppStyle = reinterpret_cast <Base2&> (d);
    Base2 & cStyle = (Base2&) d;
 

    std::cout << "reinterpret_cast:\t" << &cppStyle << '\n';
 	std::cout << "c-style:\t\t" << &cStyle << '\n';

    return 0;
}

 

komentarz 15 lutego przez Piotr Batko Gaduła (4,250 p.)
Nie wiedziałem o tym, ciekawa sprawa :) Dzięki za wyjaśnienie :)
0 głosów
odpowiedź 13 lutego przez Bondrusiek Nałogowiec (26,930 p.)

Witam,

przy dziedziczeniu w sposób publiczny możliwe są konwersje standardowe referencja/wskaźnik klasy pochodnej na referencja/wskaźnik klasy podstawowej

Przy dziedziczeniu prywatnym można też wykonać taką konwersję ale musi być to jawna konwersja.

class POCHODNA : private PODSTAWOWA
{
//ciało
};
 void funkcja(PODSTAWOWA &)
{
//ciało
}
//ciało funkcji która przyjmuje wskaźnik bądź referencje do PODSTAWOWA
//np. void funkcja(PODSTAWOWA &)

POCHODNA pochodna;//definicja
//funkcja(pochodna); błąd bo tu występuje konwersja niejawana
funkcja((PODSTAWOWA&) pochodna);//możliwe działanie bo jest tu jawna konwersja

 

Podobne pytania

0 głosów
1 odpowiedź 81 wizyt
+1 głos
5 odpowiedzi 185 wizyt
Porady nie od parady
Zadając pytanie postaraj się o szczegółowe opisanie problemu oraz udostępnienie wszystkich istotnych informacji (kody źródłowe, zrzuty ekranu itp.).
Ciekawy innych porad? Odwiedź tę stronę!

45,729 zapytań

86,123 odpowiedzi

171,990 komentarzy

22,186 pasjonatów

Przeglądających: 320
Pasjonatów: 26 Gości: 294

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...