Dziedziczenie - rzutowanie Cpp

0

Mam sytuacje następującą:

class Bazowa
{
	int x;
	int y;
public:
   	Bazowa();
   	virtual ~Bazowa();
   	int x_f(){return x;}
   	int y_f(){return y;}
   	virtual int suma(){return (x+y);}
};

class Pochodna : public Bazowa
{
   	int p;
   	int d;
 public:
   	Pochodna();
  	~Pochodna();
	virtual int suma(){return (p+d);}
};

int main()
{
	Bazowa *wsk;
	wsk=new Pochodna;		//I to jest poprawne rzutowanie w gore (upcasting)
	Pochodna *ptr;
	ptr=new Pochodna;		// I to jest moje pytanie, jak interpretować te rzutowanie? 
return 0;
}
 

Problemem jest rzutowanie, sprawia mi to pewien problem nad interpretacja jak kompilator rozumie rzutowanie w tych przypadkach, mam nawet wątpliwość dlaczego rzutowanie [wsk=new Pochodna] jest poprawne a dlaczego np [ptr=new Bazowa] (*ptr-wskaznik typu Pochodna) nie jest dobrym rozwiązaniem, przecież obszar pamieć jaki zajmuje obiekt typu Pochodna jest większa niż obiekt typu Bazowa, wiec dlaczego rzutowanie typu Pochodna *wskaznik=new Bazowa, nie zadziała?

Przeczuwam ze moja interpretacja działania rzutowania jest daleka od poprawnej dlatego prosiłbym bez hejtu :)

2

https://pl.wikipedia.org/wiki/Zasada_podstawienia_Liskov
Klasa Pochodna jest jednocześnie klasą Bazowa - dlatego mozna uzywac ptr typu Bazowa i wskazywac na Pochodna

1
Michalcpp944 napisał(a):

Mam sytuacje następującą:
obszar pamieć jaki zajmuje obiekt typu Pochodna jest większa niż obiekt typu Bazowa, wiec dlaczego rzutowanie typu Pochodna *wskaznik=new Bazowa, nie zadziała?

Skoro Pochodna zajmuje więcej miejsca w pamięci niż Bazowa, to przy przypisaniu wskaźnika Bazowej do Pochodnej, miałbyś wskaźnik na rzeczy w pamięci których tak naprawdę nie ma.

0

A nie stanie sie tak ze kompilator alokuje odpowiedni obszar pamieci i skoro obiekt typu Pochodna zajmuje wiecej miejsca to nic nie stoi na przeszkodzie by alokowac tam obiekt ktory zajmuje mniej pamieci a jedyne co robic to nie odwolywac sie do obszaru ktory jest poza implementacja i interfejsem obiektu? Moge zle to rozumiec, wiec jeszcze raz prosze bez hejtu :)

0
Michalcpp944 napisał(a):

a jedyne co robic to nie odwolywac sie do obszaru ktory jest poza implementacja i interfejsem obiektu?

Co to znaczy nie odwoływać się? Skoro klasa Pochodna ma pewne rzeczy (których nie ma w Bazowa), to dlaczego kompilator miałby zabronić odwoływać się do tych rzeczy?

0

Konwersja w górę jest automatyczna i bezpieczna, bo obiekt klasy pochodnej jest obiektem klasy bazowej (Każdy kwadrat jest prostokątem).
Należy zauważyć, że obiekt klasy pochodnej jest niemal zawsze większy od obiektu klasy bazowej. W przypadku rzutowania w górę obiektu klasy pochodnej, zostanie on przycięty.
źródło http://cpp0x.pl/kursy/Programowanie-obiektowe-C++

Czyli w moim przypadku rzutowanie np. Bazowa *ptr=new Pochodna co sie stanie, co oznacza tutaj "przycięty"?

PS. odbiegam od pytania @twonek w tym momencie dlatego ze nie jestem pewien odpowiedzi.

2
Michalcpp944 napisał(a):

Czyli w moim przypadku rzutowanie np. Bazowa *ptr=new Pochodna co sie stanie, co oznacza tutaj "przycięty"?

"Przycięty" nie jest dosłownym określeniem, bo nic nie jest obcinane. Obiekt dalej jest w pamięci w całości. Jedynie poprzez Twój wskaźnik Bazowa* nie ma dostępu do rzeczy, których nie było w bazie. Jak stworzysz sobie drugi wskaźnik Pochodna* na ten sam obiekt, to będziesz miał dostęp do wszystkiego.

3
struct B1
{
    int b1;
};

struct B2
{
    int b2;
};

struct D : public B1, public B2
{
    int d;
}

9e6583b36e.png
Zignoruj B2, to przykład do czegoś innego.

Teraz jeśli masz

B1* ptr

mówisz "Mam wskaźnik do obiektu o rozmiarze 4 kwadracików i który ma pole b1 zaczynające się w pierwszym kwadraciku". Dalej jeśli masz

ptr = new D;

kompilator Ci mówi "Dostaniesz obiekt o rozmiarze 12 kwadracików, ale nie przejmuj się tym, bo pierwsze 4 kwadraciki będą dokładnie takie jak oczekujesz i b1 będzie się zaczynał w pierwszym kwadraciku. Pozostałe 8 kwadracików zignoruj".

W drugą stronę nie bardzo działa, bo
"Mam wskaźnik do obiektu o rozmiarze 12 kwadracików"
"Dostaniesz obiekt, który ma 4 kwadraciki"
"A co jeśli chcę się odwołać do pola d w dziewiątym kwadraciku?"
"..... doopa"

0

Chyba zagadka została rozwiązana, a teraz powiem co mnie wprowadziło w błąd, mianowicie polimorfizm.

using namespace std;

class Bazowa 
{
		int x;
		int y;
	public:
		virtual int view(){return x;}
		virtual int view2(){return y;}
		Bazowa(int xx=2, int yy=3)
				: x(xx)
				, y(yy)
		{}
		virtual ~Bazowa(){};
};

class Potomna : public Bazowa
{
		int z;
		int t;
	public:
		virtual int view(){return z;}
		virtual int view2(){return t;}
		Potomna(int zz=4, int tt=6, int xx2=20, int yy2=30)
				: z(zz)
				, t(tt)
				, Bazowa(xx2, yy2)
		{}
		virtual ~Potomna(){};
};

int main(){
		Bazowa *ptr;
		ptr=new Potomna;
		cout<<ptr->view()<<endl;  // Metoda z klasy Potomnej mimo ze wskaznik typu Bazowa (polimorfizm) 
		cout<<ptr->view2()<<endl; // -||-
		return 0;
}
2
Michalcpp944 napisał(a):

Mam sytuacje następującą:


	Pochodna *ptr;
	ptr=new Pochodna;		// I to jest moje pytanie, jak interpretować te rzutowanie? 
 

Po pierwsze TO rzutowanie, a nie "te".
Po drugie tu nie ma żadnego rzutowania. Jest po prostu utworzenie wskaźnika na typ Pochodna.

0

Czuje się trochę zażenowany próba poprawiania mnie, ale póki nie mam wystarczającej wiedzy przełknę to, jednakże mam nieodparte wrażenie ze środowisko "ajti" potrzebuje jakiegoś dowartościowania się postami typu @Juhas, mam nadzieje ze to takie jednostkowe posty, bo ja tez jestem wstanie poczytać kilka postów z różnych tematów i znaleźć owe błędy ale nie w tym rzecz.

Co do tego rzutowania: wiem, ale użyłem pewnego skrótu myślowego, miałem na myśli raczej to:

Kwadrat kw;

Prostokąt p, * pp; //
p = kw; //rzutowanie w górę obiektu
pp = & kw; //rzutowanie w górę adresu 

źródło: http://cpp0x.pl/kursy/Programowanie-obiektowe-C++/Polimorfizm/Konwersja-w-gore-i-rzutowanie-w-dol/496

Nie chce wszczynać kłótni, nie mam na to czasu myślę ze wy również wiec prosiłbym użytkownika @Juhas by pohamował swoje ego. :)

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