• 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ą.

VPS Starter Arubacloud
0 głosów
792 wizyt
pytanie zadane 12 lutego 2018 w C i C++ przez SQnera Początkujący (280 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 2018 przez Patrycjerz Mędrzec (192,340 p.)
Podaj przykładowy kod.

2 odpowiedzi

+1 głos
odpowiedź 13 lutego 2018 przez j23 Mędrzec (194,920 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 2018 przez monika90 Pasjonat (22,940 p.)
edycja 13 lutego 2018 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 2018 przez j23 Mędrzec (194,920 p.)

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

komentarz 14 lutego 2018 przez Piotr Batko Stary wyjadacz (13,190 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 2018 przez j23 Mędrzec (194,920 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 2018 przez Piotr Batko Stary wyjadacz (13,190 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 2018 przez j23 Mędrzec (194,920 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 2018 przez Piotr Batko Stary wyjadacz (13,190 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 2018 przez j23 Mędrzec (194,920 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 2018 przez Piotr Batko Stary wyjadacz (13,190 p.)
Nie wiedziałem o tym, ciekawa sprawa :) Dzięki za wyjaśnienie :)
0 głosów
odpowiedź 13 lutego 2018 przez Bondrusiek Maniak (61,370 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ź 234 wizyt
0 głosów
1 odpowiedź 220 wizyt
pytanie zadane 30 kwietnia 2021 w C# przez Adamek185wp Obywatel (1,280 p.)

92,454 zapytań

141,263 odpowiedzi

319,099 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...