Anfaenger: Wie deklariert man Member Objekt und den Zugriff auf Diese ?



  • Hallo Allerseits 🙂

    Ich bin gerade dabei mich in C++ einzuarbeiten, habe aber da so meine Schwierigkeiten.
    Was das Programmieren an und fuer sich angeht bin ich recht fit da ich ein sehr sehr guter Delphi Programmierer bin.
    Daher ist OOP nicht unbekanntes fuer mich. Allerdings in C++ tickt die Uhr jedoch ein wenig anders.

    Hier also mal ein paar Fragen/Annahmen die ich gerne mal erklaert haette 🙂

    Aber Stueck fuer Stueck...
    Folgender Beispielcode (Konstruktoren und includes weggelassen):

    //Kiddy.h
    //-------
    
    class Kiddy
    {
    private:
      bool Bar;
    
    public:  
      bool GetBar();
      void SetBar(bool AValue);
    }
    
    //Kiddy.cpp
    //---------
    
    bool Kiddy::GetBar()
    {
        return Bar;
    }
    
    void Kiddy::SetBar(bool AValue)
    {
        Bar = AValue;
    }
    
    // ----------------------------------------------
    
    //Mommy.h
    //-------
    
    class Mommy
    {
    private:  
      int Foo;
      Kiddy Timmy;
      TArray<Kiddy> KiddyList;
    
    public:
      int GetFoo();
      void SetFoo(int AValue);
      Kiddy GetKiddy();
    }
    
    //Mommy.cpp
    //---------
    
    int Mommy::GetFoo()
    {
        return Foo;
    }
    
    void Mommy::SetFoo(int AValue)
    {
        Foo = AValue;
    }
    
    Kiddy Mommy::GetKiddy()
    {
        return Timmy;
    }
    
    TArray<Kiddy> Mommy::GetKiddyList()
    {
      return KiddyList;
    }
    
    void Mommy::AddKiddies(int ACount)
    {
      int x;
      Kiddy NewKid;
    
      for (x = 0; x < Acount-1; x++)
        {
          KiddyList.Add(NewKid);  
        }
      return;
    }
    

    1. Wenn ich in C++ eine Klasse als Member Objekt in einer anderen Klasse definiere, dann wird die Instanz automatisch mit der anderen Klasse erzeugt. Anders ausgedrueckt: Ich muss keinen Konstrruktor aufrufen. Die Deklaration von "Kiddy Timmy;" in Mommy alleine sorgt schon fuer die Instanzierung von Timmy. - Stimmt das?

    2. Ist das Kiddy das GetKiddy() zurueckgibt eine Kopie (as value) oder eine Referenz? Anders gefragt: Wie muss ich das deklarieren wenn ich dort wo Mommy verwendet wird Timmy ansprechen will:

    .h
    Mommy Dummy;
    
    .cpp 
    Dummy.Timmy.SetBar(true);
    

    Ebenso das Array in GetKiddyList().. Habe ich dann eine Kopie aoder das "echte" array? Oder ganz ganz anders gefragt: Wie deklariert man das als Zeiger und wie dereferenziert man das?

    3. Wie erzeuge ich ein Kiddy zur Laufzeit, beispielsweise um es in ein Array einzufuegen. Siehe AddKiddies(). Bleibt NewKid erhalten nachdem AddKiddies() out-of-scope geht? Anders gefragt: Wie muss die Implementierung vom AddKiddies() lauten damit das Array Acount individuelle Kiddy Instanzen entahelt.

    So, nun will ich aber nicht mit allen Fragen auf einmal kommen.
    Sorry wenn die Fragen etwas noobistisch erscheinen, aber C++ und Delphi unterscheiden sich doch erheblich....

    Waere echt super wenn mir jemand etwas auf die Spruenge helfen koennte 🙂

    Cheers,
    Klaus



  • Ich versuche minimal zu antworten:
    1. Stimmt, der default-Konstruktor wird aufgerufen, sofern vorhanden.
    2. Eine Kopie. Als Referenz zurückgeben ginge so:

    Kiddy& GetKiddy();
    

    3. new Kid wird bei jedem Funktionsaufruf neu instanziert und am Ende jedes Funktionsaufrufes zerstört. Deine jetztige Implementierung sorgt schon dafür, dass das Kiddie Array unabhängige Instanzen enthält: Add() sollte nämlich eine Kopie vom Kiddy speichern.

    P.S.: Keine Ahnung was das für ein Container ist, aber nimm std::vector



  • Hi,

    Vielen Dank fuer die Antwort 🙂

    Hierzu noch ein paar Fragen:

    1. Und wie geht man vor wenn man das gar nicht will, weil das Objekt erst spaeter erstellt werden soll. Anders ausgedrueckt: Angenommen Mommy erstellt Timmy erst im Laufe ihres Lebens und wenn sie es tut, dann mit bestimmten Parametern. Oder sie tut es garnicht und Timmy bleibt dann invalid, aber das kann man ja vor dem Zugriff checken..

    2. Hmm, gibt es hier in C++ einen Unterschied zwischen Seigen und Referenz? In Delphi sit das ziemlich das gleiche (und Delphi derefenziert auch noch selbsttatetig).
    Warum ich frage? Wenn ich ein Array mit einer liste von Referenzen auf Objekte speichern will, habe ich gehoert das ginge nicht. Arrays koennten nur Zeiger speichern, aber keine Referenzen.

    3. Du meinst TArray<> ? Das scheint sowas wie ein Template zu sein. Ich bastel mit C++ im Kontext der Unreal Engine 4. TArray<> ist wohl so ein Typ den Epic gebastelt hat.
    Hier ist die Referenz dazu: https://docs.unrealengine.com/latest/INT/API/Runtime/Core/Containers/TArray/index.html
    Ich muss schon diesen Container verwenden, da UE4 die Daten sonst nicht serialisieren kann.
    https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/TArrays/

    Hoffentlich steige ich da irgendwann durch 🙂

    Cheers,
    Klaus



  • Catweasel77 schrieb:

    1. Und wie geht man vor wenn man das gar nicht will, weil das Objekt erst spaeter erstellt werden soll. Anders ausgedrueckt: Angenommen Mommy erstellt Timmy erst im Laufe ihres Lebens und wenn sie es tut, dann mit bestimmten Parametern. Oder sie tut es garnicht und Timmy bleibt dann invalid, aber das kann man ja vor dem Zugriff checken..

    2. Hmm, gibt es hier in C++ einen Unterschied zwischen Seigen und Referenz? In Delphi sit das ziemlich das gleiche (und Delphi derefenziert auch noch selbsttatetig).
    Warum ich frage? Wenn ich ein Array mit einer liste von Referenzen auf Objekte speichern will, habe ich gehoert das ginge nicht. Arrays koennten nur Zeiger speichern, aber keine Referenzen.

    1. Eine Möglichkeit:

    Kiddy* timmy = nullptr; // Zeiger initialisiert als nullptr
    
    std::unique_ptr<Kiddy> timmy = nullptr; // Smartpointer
    

    Irgendwann kannst du dann:

    timmy = new Kiddy{ Parameter };
    
    timmy = std::make_unique<Kiddy>{ Parameter };
    

    Achtung bei rohen Zeigern musst du dich darum kümmern, dass der Speicher wieder freigegeben wird. Smartpointer sind die bessere Alternative.

    2. Ja! (Falls Seigen = Zeiger)

    Ich versuche auch erst seit kurzem C++ zu lernen und die Themen Zeiger, Referenz und "const" haben mich schon viel Nerven gekostet. Ich empfehle dir dich zunächst grundlegend mit diesen Themen zu beschäftigen, weil C++ hier im Vergleich zu C# oder Delphi schon anders ist.



  • Achtung bei rohen Zeigern musst du dich darum kümmern, dass der Speicher wieder freigegeben wird. Smartpointer sind die bessere Alternative

    Ja. Damit komme ich zurecht denke ich. Ist ja in Delphi nicht anders.

    2. Ja! (Falls Seigen = Zeiger)

    Ich versuche auch erst seit kurzem C++ zu lernen und die Themen Zeiger, Referenz und "const" haben mich schon viel Nerven gekostet. Ich empfehle dir dich zunächst grundlegend mit diesen Themen zu beschäftigen, weil C++ hier im Vergleich zu C# oder Delphi schon anders ist.

    Aeh.. Ja 🤡 Zeiger. Hab da wohl schneller (blind) getippt als meine Fingerchen das moechten..

    Ich versuch mal mein Glueck mit dem nullptr. Ich weiss nicht ob ich den smart pointer mit Unreal Objekten verwenden kann.
    Die haben da gleich noch mal ne ganz eigene Suppe gekocht...
    https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/SmartPointerLibrary/
    Aber da versteh ich im Moment auch nur Bahnhof und Kofferklau... 😕

    Cheers,
    Klaus

    +++ Kleines Update +++

    Nun compiliert es zwar in Visual Studio, aber die Engine schmiert ab mit einer UE4 spezifischen Fehlermeldung. Man sagt ich versuche etwas auf dem Stack zu erstellen was nicht supported sei. Wie auch immer..



  • Pointer vs Reference in C++ kann man recht gut googeln.

    Mich wundert, dass du schon mit GameEngines arbeitest, ohne mal in C++ halbwegs die Grundlagen zu lernen. Aber gut ich weiß ja nicht in welchem Kontext das Ganze steht.

    Nun compiliert es zwar in Visual Studio, aber die Engine schmiert ab mit einer UE4 spezifischen Fehlermeldung. Man sagt ich versuche etwas auf dem Stack zu erstellen was nicht supported sei. Wie auch immer..

    Schonmal die exakte Fehlermeldung in Google geschmissen (natürlich ohne Dinge wie Zeilenzahl oder Pfad etc.)? Hast du auch deinen Codeabschnitt, der das verursacht? VisualStudio hat einen recht guten debugger soweit ich weiß, da kannst du breakpoints setzten und dein Programm Schritt für Schritt ausführen lassen. Schonmal geschaut, in welcher Zeile es da knallt?



  • Pointer vs Reference in C++ kann man recht gut googeln.

    Also der Unterschied, so konzeptionell, ist mir schon klar. Nur werde ich eben mit "normalen" C++ pointern wohl nicht weit kommen.

    Mich wundert, dass du schon mit GameEngines arbeitest, ohne mal in C++ halbwegs die Grundlagen zu lernen.

    Das Problem dabei ist: Wenn ich ein C++ Tutorial durchgehe dann hilft mir das nur bedingt, da in Unreal das ganze nocheinmal etwas anders ist als "normales" C++.
    Zum Beispiel habe ich herausgefunden das man zwar in C++ Konstruktoren ueberladen kann und mit eigenen Parametern versehen kann. In UE4 ist dies jedoch nicht moeglich da das mit dem Reflection system ins Gehege kommt.

    Zusaetzliches problem ist das alle Unreal spezifischen C++ Tutorials nur maximal eine Funktion zu einer schon bestehenden Klasse hinzufuegen und das wars. Und nur mit Objekten die gerendert werden, damit man ja auch was sieht im Ergebnis. Aber ein Tutorial wie man eine reine gameplay Klasse schreibt - Fehlanzeige.

    Schonmal die exakte Fehlermeldung in Google geschmissen (natürlich ohne Dinge wie Zeilenzahl oder Pfad etc.)? Hast du auch deinen Codeabschnitt, der das verursacht? VisualStudio hat einen recht guten debugger soweit ich weiß, da kannst du breakpoints setzten und dein Programm Schritt für Schritt ausführen lassen. Schonmal geschaut, in welcher Zeile es da knallt?

    Es ist keine Visual Studio Fehlermeldung. In VS kompiliert es, aber die Engine stuerzt ab.

    das sieht dann so aus in der Unreal Engine Crash Reporter app:

    Fatal error: [File:D:\Build\++UE4+Release-4.14+Compile\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 2477] 
    UObject() constructor called but it's not the object that's currently being constructed with NewObject. Maybe you trying to construct it on the stack which is not supported.
    
    UE4Editor_Core!FDebug::AssertFailed() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\core\private\misc\assertionmacros.cpp:332]
    UE4Editor_CoreUObject!UObject::UObject() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\coreuobject\private\uobject\uobjectglobals.cpp:2478]
    UE4Editor_Code!USimpleClass::USimpleClass() [d:\ue4projects\code\source\code\private\usimpleclass.cpp:7]
    UE4Editor_Code!UComplexClass::UComplexClass() [d:\ue4projects\code\source\code\private\ucomplexclass.cpp:8]
    UE4Editor_CoreUObject!UClass::CreateDefaultObject() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\coreuobject\private\uobject\class.cpp:2664]
    UE4Editor_CoreUObject!UObjectLoadAllCompiledInDefaultProperties() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\coreuobject\private\uobject\uobjectbase.cpp:745]
    UE4Editor_CoreUObject!ProcessNewlyLoadedUObjects() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\coreuobject\private\uobject\uobjectbase.cpp:821]
    UE4Editor_CoreUObject!TBaseStaticDelegateInstance<void __cdecl(void)>::ExecuteIfSafe() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\core\public\delegates\delegateinstancesimpl.h:1018]
    UE4Editor_Core!TBaseMulticastDelegate<void>::Broadcast() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\core\public\delegates\delegatesignatureimpl.inl:922]
    UE4Editor_Core!FModuleManager::LoadModuleWithFailureReason() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\core\private\modules\modulemanager.cpp:466]
    UE4Editor_Projects!FModuleDescriptor::LoadModulesForPhase() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\projects\private\moduledescriptor.cpp:409]
    UE4Editor_Projects!FProjectManager::LoadModulesForProject() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\projects\private\projectmanager.cpp:53]
    UE4Editor!FEngineLoop::LoadStartupModules() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:2236]
    UE4Editor!FEngineLoop::PreInit() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:1668]
    UE4Editor!GuardedMain() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\launch\private\launch.cpp:113]
    UE4Editor!GuardedMainWrapper() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
    UE4Editor!WinMain() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:202]
    UE4Editor!__scrt_common_main_seh() [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:264]
    kernel32
    ntdll
    

    Was das ganze fuer einen Anfaenger noch schwerer macht: Der Code den ich schreibe ist nicht der Code der letztendlich kompiliert wird. Da werden noch zig Makros und so verwurstet.

    Nur wenn ich den Tip von oben mit dem nullptr ausprobiere, dann schmeisst es mir einen Fehler innerhalb des Epic codes in VS um die Ohren. Naemlich in der "array.h" wo der TArray<> container definiert ist. Aber da habe ich natuerlich erstrecht keinen Plan..

    Da es bei anderen Leuten wophl funktioniert muss der Fehler wohl bei mir liegen, aber mein Code wird nicht beanstandet... 😕

    Cheers,
    Klaus



  • Vielleicht magst du besser auf eine andere Engine umsteigen 👍



  • Vielleicht magst du besser auf eine andere Engine umsteigen

    Noe.. Unity ist nicht so mein Fall... 😉
    ... und die Fox engine will Konami ja nicht lizensieren...



  • Wir rufst du denn das Objekt auf? Hast du den Hinweis in der Fehlermeldung gelesen:

    Maybe you trying to construct it on the stack which is not supported.

    ?



  • Wir rufst du denn das Objekt auf? Hast du den Hinweis in der Fehlermeldung gelesen

    Ja, habe ich, aber damit kann ich nicht wirklich etwas anfangen.

    Inzwischen hab ich ein wenig weiter gebastelt und die "korrekte" Methode um ein Objekt zu erstellen scheint wohl so zu lauten:

    UStaffMember* NewStaff = NewObject<UStaffMember>();
    

    Das einfache "new" darf man in UE4 nicht verwenden (und NewObject nur bei UObject Klassen). Offensichtlich wird da einiges unter der Haube initialisiert und registriert so das "new" eben nicht reicht.

    https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Objects/Creation/


Log in to reply