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

Konferencja JOIN! 2018
0 głosów
97 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 (177,360 p.)
Podaj przykładowy kod.

2 odpowiedzi

+1 głos
odpowiedź 13 lutego przez j23 Maniak (71,520 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 Pasjonat (16,860 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 Maniak (71,520 p.)

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

komentarz 14 lutego przez Piotr Batko Mądrala (5,680 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 Maniak (71,520 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 Mądrala (5,680 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 Maniak (71,520 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 Mądrala (5,680 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 Maniak (71,520 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 Mądrala (5,680 p.)
Nie wiedziałem o tym, ciekawa sprawa :) Dzięki za wyjaśnienie :)
0 głosów
odpowiedź 13 lutego przez Bondrusiek Nałogowiec (37,340 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ź 59 wizyt
0 głosów
1 odpowiedź 61 wizyt
Porady nie od parady
Możesz ukryć, zamknąć lub zmodyfikować swoje pytanie, za pomocą przycisków znajdujących się pod nim. Nie krępuj się poprawić pochopnie opublikowanego pytania czy zamknąć go po uzyskaniu satysfakcjonującej odpowiedzi. Umożliwi to zachowanie porządku na forum.Przyciski pytania

55,340 zapytań

99,683 odpowiedzi

205,111 komentarzy

27,277 pasjonatów

Przeglądających: 313
Pasjonatów: 17 Gości: 296

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.

...