CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Problem z rzutowaniem

Problem z rzutowaniem

dział ogólny

Re: Problem z rzutowaniem

Nowy postprzez polymorphism » piątek, 9 września 2011, 20:13

To działa na tym przykładzie, bo jest prosty

Nie. Przykład działa, bo jest poprawny. Poziom skomplikowania nie ma tu nic do rzeczy.

reinterpret_cast są błędne lub nie pełne lub po prostu obiekt Klasy pochodnej nie jest obiektem klasy pochodnej

A obiekt, który rzutujesz, ten bazowy, to skąd on pochodzi, jak go tworzysz?
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Problem z rzutowaniem

Nowy postprzez Slynx » piątek, 9 września 2011, 21:02

A obiekt, który rzutujesz, ten bazowy, to skąd on pochodzi, jak go tworzysz?

Przez funkcję, która zwraca obiekt klasy bazowej wypełniony (uzupełniony odpowiednimi informacjami) lub pusty w przypadku błędu.
KOD cpp:     UKRYJ  
TBase^ GetBaseObject()
{
        TBase^ output = gcnew TBase();
        // uzupelniamy część pól...
        return output;
}
 


A to, że część pól jest niezainicjowanych w klasie bazowej, którą rzutuje na pochodną może mieć znaczenie ?
Jeśli dobrze pamiętam to konstruktor klasy bazowej nie inicjował wszystkich pól.

Nie. Przykład działa, bo jest poprawny. Poziom skomplikowania nie ma tu nic do rzeczy.

Chodziło mi o to, że nie zawiera wszystkich elementów, przedstawionych przeze mnie, które potencjalnie mogłyby sprawiać problem.
Ale mniejsza o to.
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: Problem z rzutowaniem

Nowy postprzez polymorphism » piątek, 9 września 2011, 22:42

Ech, Slynx, czytaj i analizuj to, co do Ciebie piszę! Przecież w tym poscie napisałem, że taka konstrukcja jest błędna. Ty próbujesz obiekt klasy A potraktować jak obiekt klasy B. A to błąd, ponieważ tu nie zachodzi konwersja obiektu typu A na B, jedynie konwersja wskaźnika A* na B* (w Twoim przypadku o uchwyty chodzi), zatem zmieniasz jedynie interpretację tego samego skrawka pamięci. Więc jeśli tworzysz obiekt klasy A i zaczynasz interpretować go jako obiekt klasy B, to to jest błąd. Z kolei jeśli stworzysz obiekt klasy B i zaczniesz go interpretować jako obiekt klasy A, to jest ok, ponieważ w skład obiektu klasy B wchodzi klasa A - wynika to z dziedziczenia. Mam nadzieję, że to jest teraz zrozumiałe.

Wystarczy, że zrobisz tak:
KOD cpp:     UKRYJ  
TBase^ GetBaseObject()
{
        TBase^ output = gcnew TDerived();

        // uzupelniamy część pól...

        return output;
}

i problem powinien zniknąć.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Problem z rzutowaniem

Nowy postprzez Slynx » piątek, 9 września 2011, 23:11

Teraz to jedziesz w drugą stronę. Z góry zakładasz, ze w tej funkcji ja znam jaki obiekt klasy pochodnej będzie tworzony. W tej funkcji wypełniane są TYLKO elementy klasy bazowej, bo w niej jeszcze nie jest znany wyjściowy typ obiektu. W innym przypadku całe to rzutowanie nie byłoby potrzebne.

Ja nie wiem czy w tej funkcji wyjściowej powinna być TDerived1() czy TDerived2(), więc tworzę obiekt z którego obie te klasy korzystają. A po wyjściu z funkcji, wewnątrz innej okazuje się, czy obiekt klasy bazowej (bo taki właśnie tworzę) powinien stać się obiektem TDerived1() czy TDerived2().

To co pokazałeś, to naturalnie o tym wiem, tłumaczyłeś mi to przy okazji polimorfizmu.
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: Problem z rzutowaniem

Nowy postprzez polymorphism » sobota, 10 września 2011, 10:18

Teraz to jedziesz w drugą stronę. Z góry zakładasz, ze w tej funkcji ja znam jaki obiekt klasy pochodnej będzie tworzony.

No przepraszam bardzo, ale w kontekście dziedziczenia i rzutowania w dół raczej trudno zrobić inne założenie. Jak przedstawisz problem, taką będziesz miał odpowiedź. Pisz mniej, ale konkretniej.

Jeśli teraz dobrze Ciebie rozumiem, to Tobie potrzebna jest zwykła konwersja TBase na TDerivedX:
KOD cpp:     UKRYJ  
TDerivedX^ obj = gcnew TDerivedX( GetBaseObject() );

TDerivedX musi posiadać konstruktor konwertujący, który przyjmuje w parametrze obiekt klasy TBase:
KOD cpp:     UKRYJ  
public ref class TDerivedX: public TBase
{
public:
        ...
       
        TDerivedX(TBase^ obj)
                :TBase(obj) { } //<--- TBase powinna posiadać konstruktor kopiujący
};

Inna opcja to użycie szablonu:
KOD cpp:     UKRYJ  
template<typename ClassT> TBase^ GetBaseObject()
{
        TBase^ output = gcnew ClassT();

        // uzupelniamy część pól...

        return output;
}


// użycie

TBase^ obj = GetBaseObject<TDerived1>();

...

obj = GetBaseObject<TDerived2>();
...
obj = GetBaseObject<TDerived666>();
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Problem z rzutowaniem

Nowy postprzez Slynx » sobota, 10 września 2011, 10:43

No przepraszam bardzo, ale w kontekście dziedziczenia i rzutowania w dół raczej trudno zrobić inne założenie. Jak przedstawisz problem, taką będziesz miał odpowiedź. Pisz mniej, ale konkretniej.

Przecież wyraźnie na początku napisałem że tamta funkcja zwraca obiekt bazowy, a nie jeden z pochodnych, a Ty właśnie coś takiego wkleiłeś mi do funkcji.
Zresztą już bardziej wymownej nazwy funkcji dać nie mogłem.

TDerivedX musi posiadać konstruktor konwertujący, który przyjmuje w parametrze obiekt klasy TBase:


Nie za bardzo rozumiem, to w tej klasie pochodnej (w konstruktorze z obiektem klasy bazowej), mam po kolei przypisać wszystkie elementy do klasy pochodnej ( this->a = baseObject->a; itd., itd.) ? O.o

Z tego co wyczytałem to dokładnie tak... no... czyli wróciliśmy do początku, bo takie było "awaryjne" założenie, gdy rzutowanie nie pomoże, które błędnie chciałem wykonać. Różnica, że nie będzie funkcji Copy, a wywoływanie od razu przez konstruktor, nice ;)
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: Problem z rzutowaniem

Nowy postprzez polymorphism » sobota, 10 września 2011, 11:20

Przecież wyraźnie na początku napisałem że tamta funkcja zwraca obiekt bazowy, a nie jeden z pochodnych

Od początku to my piszemy o Twoich problemach z rzutowaniem. Dopiero w momencie, gdy pokazałeś ciało funkcji GetBaseObject, wyszło w czym problem, choć już wcześniej zacząłem podejrzewać w czym rzecz, co też zasugerowałem w jednym z postów, oczywiście bez żadnej reakcji z Twojej strony, zatem założyłem, że wszystko robisz jak należy.

Zresztą już bardziej wymownej nazwy funkcji dać nie mogłem.

No, nie mogłeś. Tyle tylko, że nazwa funkcji mówi tyle, że zwraca uchwyt na obiekt TBase, nie mówi nic o tym, skąd ten obiekt pochodzi.

Nie za bardzo rozumiem, to w tej klasie pochodnej (w konstruktorze z obiektem klasy bazowej), mam po kolei przypisać wszystkie elementy do klasy pochodnej ( this->a = baseObject->a; itd., itd.) ? O.o

Jeśli domyślny konstruktor kopiujący nie wystarczy, to tak.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Problem z rzutowaniem

Nowy postprzez Slynx » poniedziałek, 12 września 2011, 13:14

Jeszcze mam jedno pytanie, bo wyczytałem coś. Wątpię by dotyczyło języków zarządzanych, ale wolę się upewnić.
Chodzi o przypisywanie w konstruktorze z obiektu podanego w argumencie:
KOD cpp:     UKRYJ  
TDerivedX(TBase^ obj)
{
// opt1
this->field1 = obj->field1;
// opt2
this->field1 = gcnew String(obj->field1);
}
 

Chodzi o to, że przy przypisaniu, tak jak ma to miejsce w opcji 1, przypisywana jest tylko wartość czy włącznie z adresem ? Jako, że to konstruktor, to obiekty są niezainicjowane. Jeśli przypisze mu ten sam adres w pamięci, który miał obj->field1, to gdy dojdzie do niszczenia obiektu, zostaną zniszczone również dane obiektu TDerivedX, jako, że pola posiadają ten sam adres w pamięci.

Druga opcja jest bezpieczniejsza bo inicjuje zmienną wartością obj->field1, przypisując obiektowi (this->field1) nowy adres w pamięci.

Czy trzeba brać to pod uwagę czy coś takiego nie grozi ?
Nie jestem pewien, bo jak testowałem i chciałem zniszczyć ten obiekt (delete) to GC go trzymał do czasu aż nie zniszczyłem tego drugiego.
Na razie zrobię wersją 1, a potem najwyżej się poprawi.

------------------------

Ok, już sprawdziłem dla typów int i String^ wbudowanym disassemblerem. Mają inne adresy w pamięci, więc dla każdego innego typu obiektu będzie to działać tak samo. Niepotrzebny post.
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: Problem z rzutowaniem

Nowy postprzez polymorphism » poniedziałek, 12 września 2011, 14:17

Chodzi o to, że przy przypisaniu, tak jak ma to miejsce w opcji 1, przypisywana jest tylko wartość czy włącznie z adresem ?

Masło maślane ;) Dobrze by było, jakbyś zaczął w końcu rozróżniać obiekt od uchwytu/wskaźnika/referencji do niego. Opcja pierwsza to przepisanie uchwytu, czyli ten sam obiekt jest współdzielony w dwóch instancjach klasy TDerivedX. W tym przypadku obiekt jest zarządzany, więc nie ma problemu odpowiedzialności za zniszczenie go. Dodatkowo NETowy String jest immutable, czyli tylko do odczytu, zatem zmiana zawartości tego pola w jednej klasie nie będzie wpływać na jego stan w drugiej. W przypadku zwykłych wskaźników opcja pierwsza byłaby problematyczna. Dlatego między innymi powinno się implementować konstruktor kopiujący i operator przypisania klasom, które zarządzają jakąś pamięcią.

Opcja druga tworzy kopię, ale w zarządzanych obiektach immutable jest to - jak sądzę - niepotrzebne.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Poprzednia strona

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 3 gości