Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
cpp:oop:start [2010/03/04 22:13]
xin
cpp:oop:start [2022/09/22 19:58] (aktuell)
Zeile 1: Zeile 1:
-====== ​Was ist objektorientierte ​Programmierung======+====== ​Objektorientierte ​Programmierung ======
  
-Mancher wird sich wundern, wieso objektorientierte ​Programmierung ​jetzt erst im Tutorial auftaucht, schließlich sind Klassen bereits bekannt und auch Information-Hiding (public, protected, private) ​ist bereits bekannt. Auch wenn man es von Lehrern an Schulen oder Professoren an den Hochschulen so beigebracht bekommt, dass dies Teile der objektorientierten Programmierung wären - alles Quatschbisher tauchte im Tutorial noch überhaupt keine objektorientierte Programmierung ​auf.+Objektorientierte ​Programmierung ist ein Schlagwort in der Informatikaber eine klare Abgrenzung, was objektorientierte Programmierung ​eigentlich ist, fällt selbst vielen professionellen Entwicklern schwer.
  
-Das wollen wir nun ändern. Beginnen wir damit, uns zunächst bewusst zu machen, was OOP überhaupt ​ist. Wenn wir uns an einem Objekt orientieren,​ dann müssen wir das Objekt fragen, welche Art Objekt es denn gerne sein möchte. Ein Beispiel:+  * [[explanation|Was ​ist objektorientierte Programmierung?​]] 
 +  * [[funcptr|Objektorientierung über Funktionspointer]] 
 +  * [[vtable|Objekttyp-orientierte Programmierung]] ​  
 +  * [[virtual|virtuelle Methoden]] Objekttyporientierte Programmierung mit C++ 
 +  * [[destruct|virtuelle Destruktoren]] Objekttyporientierter Abbau von Objekten 
 +  * [[interface|Interfaces]] (Pure virtual methods)
  
-<code cpp> +Mit der Objekt(typ)-Orientierten Programmierung erhält C++ über die Typindentifikation die Möglichkeit zur Laufzeit Typinformationen abzufragen.
-enum ObjType +
-+
-  OBJTYPE_LINE,​ +
-  OBJTYPE_CIRCLE,​ +
-  OBJTYPE_RECT ​  +
-}+
  
-struct GraphicElement +  * [[rtti|Run-Time-Type-Information]] (RTTI) 
-+  ​* [[cpp:​cast:​dynamic_cast|Dynamische Casts]] ​
-  ObjType ​Type; +
-  ​ +
-  double XPosition, YPosition;​ +
-  double Additional1,​ Additional2;​ +
-}; +
-</​code>​+
  
-Eine Instanz von GraphicElement,​ beschreibt mit Type die Art des Objektes, die es darstellt. Nun kann man Funktionen schreiben, die //​objektorientiert//​ arbeiten: 
- 
-<code cpp> 
-void DrawElement( struct GraphicElement * element ) 
-{ 
-  switch( element->​Type ) 
-  { 
-    case OBJTYPE_LINE: ​  ​DrawLine ​ ( XPosition, YPosition, Additional1 /* X2 */ , Addition2 /* Y2 */ ); break; 
-    case OBJTYPE_CIRCLE:​ DrawCircle( XPosition, YPosition, Additional1 /* Radius */ ); break; ​ 
-    case OBJTYPE_RECT: ​  ​DrawRect ​ ( XPosition, YPosition, Additional1 /* Width */, Addition2 /* Height */ ); break; 
-  }  ​ 
-} 
- 
-double CalcArea( struct GraphicElement * element ) 
-{ 
-  switch( element->​Type ) 
-  { 
-    case OBJTYPE_LINE: ​  ​return 0.0; 
-    case OBJTYPE_CIRCLE:​ return 6.28319 * element->​Additional1 * element->​Aditional;​ // 2*pi*radius^2 ​ 
-    case OBJTYPE_RECT: ​  ​return element->​Additional1*element->​Additional2;​ 
-  }  ​ 
-  
-  return 0.0;  
-} 
-</​code>​ 
- 
-Das ist Objektorientiert. Und wichtig ist, dass hier nichts verwendet wurde, was C++ erfordert, denn Objektorientierte Programmierung ist auch in C möglich. Und um zu verstehen, was OOP ist, werden wir uns OOP in C anschauen und dann sehen, wie C++ uns dabei unterstützt. 
- 
-Hier lässt sich der Objekttyp einfach durch das setzen der Variable ''​Type''​ des ''​GraphicElement''​s setzen und verändern. Die beiden Funktionen ''​DrawElement''​ und ''​CalcArea''​ entscheiden nun in Abhängigkeit zum Member ''​Type'',​ wie sie ablaufen sollen. Wir können diese Entscheidung nun aber auch gleich dem Objekt überlassen,​ indem wir sie um die entsprechenden Funktionspointer erweitern: 
- 
-<code cpp> 
-struct GraphicElement 
-{ 
-  ObjType Type; 
-  ​ 
-  double XPosition, YPosition; 
-  double Additional1,​ Additional2;​ 
-  
-  void (*Draw)( struct GraphicElement * ); 
-  double (*CalcArea)( struct GraphicElement * );  ​ 
-}; 
-</​code>​ 
- 
-Ab nun wird der ObjType eigentlich nicht mehr benötigt, da nun zwei Funktionszeiger festlegen, welche Funktionen gerufen werden sollen: 
- 
-<code cpp> 
-void DrawLine( struct GraphicElement * element ) { DrawCircle( element->​XPosition,​ element->​YPosition,​ element->​Radius ); } 
-void DrawLine( struct GraphicElement * element ) { DrawLine( element->​XPosition,​ element->​YPosition,​ element->​Additional1,​ element->​Addition2 ); } 
-void DrawRect( struct GraphicElement * element ) { DrawRect( element->​XPosition,​ element->​YPosition,​ element->​Additional1,​ element->​Addition2 ); } 
- 
-double CalcAreaLine( struct GraphicElement * element ) { return 0.0; } 
-double CalcAreaLine( struct GraphicElement * element ) { return 6.28319 * Additional1 * Aditional; } 
-double CalcAreaLine( struct GraphicElement * element ) { return Width*Height;​ } 
- 
-GraphicElement * NewCircle( double x, double y, double radius ) 
-{ 
-  GraphicElement * result = (GraphicElement *)malloc( sizeof( GraphicElement ) ); 
-  
-  if( result ) 
-  { 
-    result->​ObjectType = OBJTYPE_CIRCLE;​ 
-  
-    result->​XPosition = x; 
-    result->​YPosition = y; 
-    result->​Additional1 = r; 
-    result->​Draw = DrawCircle; 
-    result->​CalcArea = CalcAreaCircle; ​ 
-  } 
- 
-  return result; ​   
-} 
- 
-int main( void ) 
-{ 
-  GraphicElement *ge; 
-  
-  ge = NewCircle( 5.0, 5.0, 2.5 ); 
-  
-  printf( "​Fläsche des Kreises: %f", ge->​CalcArea( ge ) ); 
-  
-  free( ge ); 
-  
-  return EXIT_SUCCESS;  ​ 
-}</​code>​ 
- 
-Auch dies ist objektorientierte Programmierung. Grundsätzlich kann sich jedes Objekt entscheiden,​ welche Draw-Routine und welche CalcArea-Routine verwendet wird. Aber in der Regel ist dies so auch gar nicht erforderlich,​ zumeist orientiert man sich am Datentyp des Objektes. Ein Kreis wird also nicht mit der DrawLine-Funktion gezeichnet und die Fläche nicht der CalcAreaRect-Funktion berechnet. Es wird also immer so sein, dass ein Typ einen Satz von Funktionen verwendet. 
- 
-Objektorientierte Programmierung sollte also eher Objekttyporientierte Programmierung heißen, wenn man es genau nimmt. Schauen wir uns nun die übliche Implementierung an, wie Objekt(typ)orientierte Programme aufgebaut werden. Wenn die Funktionen grundsätzlich vom Typ abhängen, so müssen Objekte nicht mehr jedes für sich alle Funktionspointer mitführen, es reicht aus, wenn es eine Tabelle gibt, die den Typ beschreibt: 
- 
-<code cpp> 
-struct GraphicObjectVTable 
-{ 
-  ObjType Type; 
- 
-  void (*Draw)( struct GraphicElement * ); 
-  double (*CalcArea)( struct GraphicElement * );  ​ 
-}; 
- 
-struct GraphicElement 
-{ 
-  GraphicObjectVTable * vtable; 
-  ​ 
-  double XPosition, YPosition; 
-  double Additional1,​ Additional2; ​ 
-}; 
- 
-struct GraphicObjectVTable GraphicObjectVTableLine;​ 
-struct GraphicObjectVTable GraphicObjectVTableCircle;​ 
-struct GraphicObjectVTable GraphicObjectVTableRect; ​ 
- 
-void initVTables() 
-{ 
-  GraphicObjectVTableLine.Type = OBJTYPE_LINE;​ 
-  GraphicObjectVTableLine.Draw = DrawLine; 
-  GraphicObjectVTableLine.CalcArea = CalcAreaLine;​ 
- 
-  GraphicObjectVTableCircle.Type = OBJTYPE_CIRCLE;​ 
-  GraphicObjectVTableCircle.Draw = DrawCircle; 
-  GraphicObjectVTableCircle.CalcArea = CalcAreaCircle;​ 
- 
-  GraphicObjectVTableRect.Type = OBJTYPE_RECT;​ 
-  GraphicObjectVTableRect.Draw = DrawRECT; 
-  GraphicObjectVTableRect.CalcArea = CalcAreaRect;​ 
-} 
- 
-GraphicElement * NewCircle( double x, double y, double radius ) 
-{ 
-  GraphicElement * result = (GraphicElement *)malloc( sizeof( GraphicElement ) ); 
-  
-  if( result ) 
-  { 
-    result->​vtable = &​GraphicObjectVTableCircle;​ 
-  
-    result->​XPosition = x; 
-    result->​YPosition = y; 
-    result->​Additional1 = r; 
-  } 
- 
-  return result; ​   
-} 
- 
-int main( void ) 
-{ 
-  initVTables();​ 
- 
-  GraphicElement *ge; 
-  
-  ge = NewCircle( 5.0, 5.0, 2.5 ); 
-  
-  printf( "​Fläsche des Kreises: %f", ge->​vtable->​CalcArea( ge ) ); 
-  
-  free( ge ); 
-  
-  return EXIT_SUCCESS;  ​ 
-}</​code>​ 
- 
-Dies ist nun ein Programm, was abhängig vom Objekttyp unterschiedliche Methoden ruft. Je nach Objekttyp hat das Objekt eine andere Instanz der ''​struct GraphicObjectVTable'',​ anhand der entschieden wird, welche Funktion nun gewählt wird. Anhand des Objektes wird die Funktion gewählt und ihr das Objekt übergeben. Das übergebene Objekt wird in C++ innerhalb der Methode mit dem Schlüsselwort ''​this''​ angesprochen.