Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

11

22.08.2012, 18:43

Ich finde es irgendwie nicht sinnlos... ich glaube da kann man sich streiten.

Nein, kann man nicht. Es ist einfach Blödsinn.

Also führt kein Weg an überladenen Funktionen vorbei?

Du hast die Wahl. Entweder verwendest du einen Hammer um den Nagel in die Wand zu hauen oder du verwendest einen Schraubendreher und rammst dir den Nagel in die Hand.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

12

22.08.2012, 18:51

Was genau willst du mit den Listen denn tun? If-Kaskaden nach Typ sind praktisch nie eine gute Idee, in diesem Fall sind Overloads oder dynamische Bindung die richtige Wahl. Um dir sinnvoll helfen zu können, bedarf es jedoch mehr Kontext.
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

13

22.08.2012, 19:08

Zitat

Nein, kann man nicht. Es ist einfach Blödsinn.

Mhh... ich finde das:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
template <class T>
void doStuff(T &obj)
{
   if(typeid(obj) == typeid(xyz)) // rufe funktion zyx() auf
   if(typeid(obj) == typeid(abc)) // rufe funktion cba() auf
   if(typeid(obj) == typeid(def)) // rufe funktion fed() auf
   // usw.
}

viel übersichtlicher und leichter zu warten, als dass hier:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
void doStuff(xyz &obj)
{
   // rufe funktion zyx() auf
}

void doStuff(abc &obj)
{
   // rufe funktion cba() auf
}

// usw.

...

Naja..., in meinem Fall scheint dann wohl wirklich kein weg an überladenen Funktionen zu führen.
Aber was hätte es denn mit dynamischer Bindung auf sich? Was muss ich da drunter verstehen? (jaja, bin schon am googeln)

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

15

22.08.2012, 19:19


Mhh... ich finde das viel übersichtlicher und leichter zu warten, als dass hier:[/quote]

Noch viel übersichtlicher ist:

C-/C++-Quelltext

1
2
3
4
void doStuff( const BaseClass& object )
{
   object.doXYZ();
}

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

16

22.08.2012, 19:44

Mhh... ich finde das: [...] viel übersichtlicher und leichter zu warten, als dass hier: [...]

Nein, Ersteres ist bezüglich Wartbarkeit ein Albtraum. Wenn ein Objekttyp fehlt (z.B. weil du später einen neuen einführst), merkst du das in deinem Chaos von ifs nicht mal. Mit Überladungen siehst du hingegen sofort, dass ein Objekttyp fehlt, weil der Compiler dir genau dies in einer Fehlermeldung mitteilt, sobald du "doStuff()" mit einem unbekannten Objekttyp aufrufst.
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

17

22.08.2012, 19:47

Zitat

Cat meint virtuelle Methoden.

Achso..., Danke. Werde dann wohl jetzt anfangen rum zu experimentieren, um das Verständnis dafür zu erhöhen!

Zitat

Noch viel übersichtlicher ist:

C-/C++-Quelltext

1
2
3
4
void doStuff( const BaseClass& object )
{
   object.doXYZ();
}

Das geht aber allerdings auch nur, wenn im Beispiel alle Klassen von der gleichen BaseKlasse
erben, ansonsten ist es immer noch mehr schreib Aufwand und alles muss einzeln gewartet werden...

@CodingCat das lässt sich aber mit einem "else" und einem Logfile Eintrag oder einem absichtlich herbeigerufenen Fehler / Absturz
auch beim ersten Code Beispiel bewerkstelligen, dann merkt man auch schnell, das etwas fehlt.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Jack« (22.08.2012, 19:52)


drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

18

22.08.2012, 20:15

@CodingCat das lässt sich aber mit einem "else" und einem Logfile Eintrag oder einem absichtlich herbeigerufenen Fehler / Absturz
auch beim ersten Code Beispiel bewerkstelligen, dann merkt man auch schnell, das etwas fehlt.

Grundsätzlich sollte man so programmieren, dass Fehler möglichst früh entdeckt werden. Das spart viel Zeit (weil es nicht mehr getestet werden muss) und verhindert auch, dass die Fehler erst zu spät bemerkt und das Debuggen dann komplizierter wird.

Du aber führst unnötige Laufzeitvergleiche ein, obwohl das bereits der Compiler machen und überprüfen kann.

Das ist etwas, worüber erfahrenere Programmieren kaum streiten. Ist einfach schlecht das so zu machen.

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

19

22.08.2012, 21:04

Im Übrigen ist die Variante mit den Überladungen auch wesentlich effizienter, weil sie nicht erst bei jedem add() alle Typen einzeln durchtesten muss, sondern schon zur Compile-Zeit die richtige Liste feststeht und somit zur Laufzeit ohne Suche direkt genutzt wird. Eine mögliche Lösung mit dynamischer Bindung wäre zum Beispiel Folgendes, aber das ist so übergenerisch und umständlich, dass du mit wenigen Overloads wesentlich besser dran bist. ;)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
size_t allocateTypeID()
{
   // In multi-threaded Umgebungen müsste hier synchronisiert werden
   static size_t nextTypeID = 0;
   return nextTypeID++;
}

template <class T>
inline size_t getTypeID()
{
   // Vor C++11 müsste hier atomar auf Initialisierung geprüft werden
   static const size_t typeID = allocateTypeID();
   return typeID;
}

struct AnyCollection
{
   virtual ~AnyCollection() { }
   virtual void add(const void &r) = 0;
   virtual void remove(const void &r) = 0;
   // Operations on lists
};

template <class T>
struct TypedCollection : public AnyCollection
{
   std::list<T> list;

   void add(const void &r) { list.push_back( static_cast<const T&>(r) ); }
   void remove(const void &r) { list.remove( static_cast<const T&>(r) ); }
   // Operations on typed list
};

struct CollectionsByType
{
   std::vector< std::unique_ptr<AnyCollection> > lists;

   template <class T>
   void add(const T &e)
   {
      size_t typeID = getTypeID<T>();
      if (typeID >= lists.size())
      {
         lists.resize(typeID + 1);
         lists[typeID].reset( new TypedCollection<T>() );
      }
      lists[typeID]->add(e);
   }
   template <class T>
   void remove(const T &e)
   {
      size_t typeID = getTypeID<T>();
      if (typeID < lists.size())
         lists[typeID]->remove(e);
   }
};
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »CodingCat« (22.08.2012, 21:15)


20

22.08.2012, 21:18

@drakon
... Mhh... Ich finde das Argument unbefriedigend, wenn ich jetzt stur wäre, würde ich immer noch darauf beharren das dass
Erstere besser aussieht und besser wartbar ist, außerdem ist der kurze Blick in die Logfile welcher das selbe Ergebnis wie der Blick auf
die Compiler Ausgaben bringt, auch wenn das vielleicht wirklich ein paar Sekunden länger dauert, hinnehmbar.

Aber ich akzeptiere mal eure Meinung und halte mich mal ausnahmsweise an die "Norm". ^^

@CodingCat
Danke. Ich werde mir das ganze mal in ruhe genauer anschauen. :)

Werbeanzeige