2016-03-31 8 views
24
#include<iostream> 
using namespace std; 

class A { 
    public: 
    void f(){cout<<"A"<<endl;} 
}; 

class B : private A { 
    public: 
    void f(){cout<<"B"<<endl;} 
}; 

int main(){ 

Jako klasa B dziedziczy klasy A prywatnie, to upcasting nie ma pracować:Dlaczego jawne typowanie pozwala na upcasting dla prywatnego dziedziczenia?

A* a = new B; 

Ale jawne typecasting jest umożliwienie go. Dlaczego?

A* a1 = (A*)new B; 
    a1->f(); 
    return 0; 
} 
+1

C-cast pozwala na większość konwersji (nawet od 'int *' do 'A *'). Wykorzystanie może być wtedy UB z oczekiwanym wynikiem. – Jarod42

+0

Duplikat: http://stackoverflow.com/questions/17925124/can-i-cast-a-derived-class-to-a-private-base-class-c –

Odpowiedz

18

Obsada w

A* a1 = (A*)new B; 

jest obsada do niedostępnej klasy bazowej.

Można go wyrazić tylko jako odlew w stylu C. Jest to odpowiednik tego, co zrobiłby static_cast, gdyby można było użyć static_cast w tej sytuacji i nie jest to równoważne z reinterpret_cast. W szczególności adres wyniku niekoniecznie musi być taki sam, jak adres argumentu.

C++ 11 §5.4/4:

The same semantic restrictions and behaviors [as for a static_cast ] apply [for a C style cast], with the exception that in performing a static_cast in the following situations the conversion is valid even if the base class is inaccessible:

— a pointer to an object of derived class type or an lvalue or rvalue of derived class type may be explicitly converted to a pointer or reference to an unambiguous base class type, respectively;

+2

Jeśli to niemożliwe wyrażone w kategoriach reinterpret_cast i const_cast, to w ogóle nie jest prawidłowym rzutem. –

+5

@RichardHodges: Przesyłanie do niedostępnej klasy bazowej i 'dynamic_cast', a nawet' static_cast' dla ogólnego przypadku, nie mogą być wyrażone w terminach 'reinterpret_cast' i' const_cast'. To znaczy. twoje stwierdzenie, że "jeśli nie można go wyrazić w kategoriach reinterpret_cast i const_cast, to w ogóle nie jest prawidłowym rzutem" jest bezsensownym stwierdzeniem. Przepraszam. –

+1

Widzę referencje i stoję poprawione. Dziękuję Ci. –

5

Jawne rzucanie pozwala zrobić wszystko, co chcesz. Możesz na przykład napisać:

int *p = (int*)new B; 

, a kod zostanie skompilowany. Jawne rzucanie oznacza, że ​​wiesz, co robisz.

+12

* Wyraźny rzut oznacza, że ​​wiesz, co robisz . * => zwykle odwrotnie. :-) – HostileFork

+0

^^ absolutnie to !!! –

+0

Jawne rzutowanie mówi kompilatorowi, że "Wiem, co robię" –

8

Jest to dozwolone przez przepisy stylu C rzuca:

(N3337) [expr.cast]/4 : The conversions performed by

  • a const_cast (5.2.11),
  • a static_cast (5.2.9),
  • a static_cast followed by a const_cast,
  • a reinterpret_cast (5.2.10), or
  • a reinterpret_cast followed by a const_cast,

can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply, with the exception that in performing a static_cast in the following situations the conversion is valid even if the base class is inaccessible:

  • a pointer to an object of derived class type or an lvalue or rvalue of derived class type may be explicit converted to a pointer or reference to an unambiguous base class type, respectively;

  • [...]

Jeśli zmieni się static_cast, to zawiedzie kompilować. GCC podaje ten błąd:

error: 'A' is an inaccessible base of 'B' 
    A* a1 = static_cast<A*>(new B); 
1

Wykreślone typowanie jest funkcją programowania języka C, która nie ma żadnych funkcji lub zasad orientacji obiektowej. Dla języka C wszystko wskazuje na wskaźniki (do pamięci lub funkcji). Aktualizacje i downcasting to funkcje orientacji obiektowej zapewniane przez C++. Rzucanie dziedziczenia musi zachowywać się zgodnie z zasadami orientacji obiektowej języka. Jednak poprzez typowanie obiektu podobnego do tego: A* a1 = (A*)new B; wymuszasz kompilator traktując obiekt jako A, tak jak robisz to w C, zmuszając wskaźnik struktury do innego. Dlatego, gdy kompilator decyduje, który wskaźnik funkcji przypisać do wskaźnika wywołującego rzutowanego obiektu f(), przydziela on wskaźnik implementacji klasy A.

+0

Myślę, że jest to najbardziej odpowiednia odpowiedź, ponieważ op pyta, dlaczego. –

Powiązane problemy