C++ saját osztály kasztolása

C++ saját osztály kasztolása
2019-01-15T20:53:00+01:00
2019-01-17T14:24:40+01:00
2022-10-15T21:30:50+02:00
Amdni
Üdv!

Most ismerkedem a c++-al, a kasztolással nagyon elakadtam.

van egy egitest típus
továbbá bolygó és csillag típus, ezeknek az őse az egitest.
Egy listában szeretnék őket tárolni.
list<egietst> lista;

Szeretném kiolvasáskor megállapítani hogy pl. bolygó-e, és utána kasztolni az eredeti típusra, de nem tudom megoldani, alá van húzva a "b" betű.

bolygo temp;
for (Egitest* b : EgitestLista) {
if (typeid(Bolygo) == typeid(b)) {           
            temp = dynamic_cast<Bolygo*>(b); //itt a hiba!
        
Ebben kérnék segítséget.
Köszönöm.
Mutasd a teljes hozzászólást!
Csatolt állomány
Hát, ez a feladat hosszabb, mint érdekes:(

Szerintem jó feladat új dolgok tanulására.

#include <vector> #include <variant> #include <string> #include <type_traits> class Egitest { public: private: std::string azonosito; std::string nev; double kor; }; class Bolygo final : public Egitest { public: enum class Osztaly { kozet, orias }; auto get_keringesi_tavolsag() const noexcept { return keringesi_tavolsag; } private: Osztaly osztaly; double keringesi_tavolsag; }; class Csillag final : public Egitest { public: enum class Osztaly { atlagos, voros_orias, barna_torpe, neutron, hullo }; private: Osztaly osztaly; double atmero; }; using Vilagur = std::vector<std::variant<Bolygo, Csillag>>; template <typename... Ts> void hozzaad(Vilagur& vilagur, Ts&&... ts) { (vilagur.push_back(std::forward<Ts>(ts)), ...); } auto akt(const Vilagur& vilagur) { double sum = 0; Vilagur::size_type count = 0; for (const auto& egitest : vilagur) { if (auto bolygo = std::get_if<Bolygo>(&egitest)) { sum += bolygo->get_keringesi_tavolsag(); ++count; } } return sum / count; } int main() { Vilagur vilagur; hozzaad(vilagur, Bolygo{}, Csillag{}, Bolygo{}); akt(vilagur); }
Mutasd a teljes hozzászólást!

  • Az Égitest bármikor helyettesíthető egy Bolygóval, mivel az a leszármazottja, de fordítva ez nem igaz. Ha Bolygón akarsz bolygóspecifikus műveletet végezni, és ehhez típusellenőrzés vagy kasztolás kell, az szembemegy az OOP alapelveivel, valami koncepcionális hiba van. Mi lenne a végcél itt? Hátha találunk jobb megoldást.
    Mutasd a teljes hozzászólást!
  • Az itt leírt szövegednél list<egietst> lista; egy nem pointereket tároló tömb, az alább látható kódodnál a for ciklusban pedig már pointert használsz, de a kasztnál a bolygo megint nem pointer. A képen lévő kódod meg megint teljesen más.

    Nézd meg itt a minta kódot: dynamic_cast conversion - cppreference.com
    Mutasd a teljes hozzászólást!
  • Itt egy hasonló kérdés, csak más programnyelvhez: https://prog.hu/tarsalgo/195398/java-hogy-tudom-a-kattintott-gomb-in..
    Mutasd a teljes hozzászólást!
  • Naszóval az instanceof helyett a használható a dynamic cast, ha a RTTI is úgy akarja.
    Mutasd a teljes hozzászólást!
  • Kozben átírtam, egy virtuális metódust helyeztem ez az ősosztályban, és így már nem jelez hibát a visual studio. Igaz most nem értem hogy miért fut a program, mivel a gyermekosztályban nem overridoltam a virtuális metódust. (visual c++).

    A feladatot mellékelem.
    Ez a feladatrész az amivel elakadtam:
    Írj metódust, mely visszaadja a bolygók átlagos keringési távolságát!
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • A jelenlegi programkód.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Csak 1 megjegyzés:
    az EgitestLista ugye a csillagokat is tartalmazza, tehát, ha az átlagszámításnál (ami ugye csak a bolygókra vonatkozik) ennek a méretével számolsz (osztasz), akkor az elrontja a végeredményt.
    Mutasd a teljes hozzászólást!
  • Hát, ez a feladat hosszabb, mint érdekes:(

    Szerintem a listán csak pointerek legyenek, és a sikeres dynamic_cast jelentse azt, hogy bolygó. (Ehhez kell a RTTI nevű mágia, bármi is legyen az.) 

    Vagy lehetne az égitestnek egy 'égitest_típus' mezője, azzal a kiegészítéssel, hogy az értékek egy enum-ból valók, pl.: Egyeb,Bolygó,Csillag,<jövőbelifejlesztésekhelye>. Az Égitest konstruktora 'Egyéb'-bel tölti az 'égitest_típust', hogy a jövőbeli fejlesztések még véletlenül se akadjanak össze a meglévőkkel.
    Mutasd a teljes hozzászólást!
  • Hát, ez a feladat hosszabb, mint érdekes:(

    Szerintem jó feladat új dolgok tanulására.

    #include <vector> #include <variant> #include <string> #include <type_traits> class Egitest { public: private: std::string azonosito; std::string nev; double kor; }; class Bolygo final : public Egitest { public: enum class Osztaly { kozet, orias }; auto get_keringesi_tavolsag() const noexcept { return keringesi_tavolsag; } private: Osztaly osztaly; double keringesi_tavolsag; }; class Csillag final : public Egitest { public: enum class Osztaly { atlagos, voros_orias, barna_torpe, neutron, hullo }; private: Osztaly osztaly; double atmero; }; using Vilagur = std::vector<std::variant<Bolygo, Csillag>>; template <typename... Ts> void hozzaad(Vilagur& vilagur, Ts&&... ts) { (vilagur.push_back(std::forward<Ts>(ts)), ...); } auto akt(const Vilagur& vilagur) { double sum = 0; Vilagur::size_type count = 0; for (const auto& egitest : vilagur) { if (auto bolygo = std::get_if<Bolygo>(&egitest)) { sum += bolygo->get_keringesi_tavolsag(); ++count; } } return sum / count; } int main() { Vilagur vilagur; hozzaad(vilagur, Bolygo{}, Csillag{}, Bolygo{}); akt(vilagur); }
    Mutasd a teljes hozzászólást!
  • Ezt az enumos dolgot ne... Iszonyatos antipattern.
    Mutasd a teljes hozzászólást!
  • Nyilván, de azért megpróbálhatsz a saját szavaiddal érvelni ellene...
    Mutasd a teljes hozzászólást!
  • Pont, hogy a további fejlesztéseket teszi ez iszonyat kényelmetlenné. Egy lib-be belefordított enum nem igazán bővíthető. És még ha bővítenéd is, ki tudja, hány helyen használja már valaki azt az eddigi értékkészletével.
    Még milyen jó, hogy van RTTI, ami a megoldás az adott problémára :)
    Mutasd a teljes hozzászólást!
  • Köszönöm, így sokkal jobb: ha vannak érvek, tudunk róluk beszélgetni, vitatkozni.

    > Egy lib-be belefordított enum nem igazán bővíthető.

    Mondjuk C++-ban pont az a jó, hogy nincs 'fekete doboz elv', azaz nincs specifikáció és implementáció szétválasztása, már egy privát adattag hozzáadása esetén is újra kell fordítanod mindent.
    Persze ettől még a meglátásod jogos, ha ez termékké fejlődne, akkor rögzítenénk, hogy 0=unspecified, 1-2 használatban, 3-300 fejlesztésre fenntartva, 301-től felhasználói (vö: WM_USER a Windows-ban).

    > Még milyen jó, hogy van RTTI, ami a megoldás az adott problémára :)

    Bár a kérdező kolléga is kimérte, hogy nem feltétlenül van RTTI. Wiki:

    RTTI is available only for classes that are polymorphic, which means they have at least one virtual method. In practice, this is not a limitation because base classes must have a virtual destructor to allow objects of derived classes to perform proper cleanup if they are deleted from a base pointer.

    RTTI is optional with some compilers; the programmer can choose at compile time whether to include the functionality. There may be a resource cost to making RTTI available even if a program does not use it.
    Mutasd a teljes hozzászólást!
  • Szerintem nézz körül a visitor_pattern és a double dispatch környékén.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd