Objektorientiert Programmieren in C

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Objektorientiert Programmieren in C

Beitrag von Dirty Oerti » Di Dez 16, 2008 10:07 pm

Tag :)
Simple Frage:
Wie programmiert man "objektorientiert" in C?

MfG
Daniel
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Objektorientiert Programmieren in C

Beitrag von Xin » Di Dez 16, 2008 11:15 pm

Ich interepretiere Deine Frage mal so, wie Du meinst... und wie Du sie vermutlich auch beigebracht bekommen hast. Die Informatik ist eine Wissenschaft, die sehr logisch ist, aber sobald man sie mit menschlicher Sprache umschreibt, so bleibt da oftmals nicht viel von über.
"Objektorientierte Programmierung" ist ein gutes Beispiel dafür.


Also... da gibt es viele Möglichkeiten.

Klassifizieren kann man auch mit Strukturen, genauso ableiten:

Code: Alles auswählen

struct Base
{
  int id;
  int BaseValue;
};

struct DerivedA
{
  struct Base myBase;
  int ValueA;
};

struct DerivedB
{
  struct Base myBase;
  int ValueB;
};

Entsprechend braucht man Konstruktoren (Funktionen, die ein DerivedA oder DerivedB zurückgeben), die die 'id' entsprechend setzen.
Eine Methode ist eine normale Funktion, die als erstes Argument allerdings das entsprechende Objekt hat. Eine Methode, die in einer abgeleiteten Klasse benutzt wird, sieht dann so aus:

Code: Alles auswählen

void MethodForA( struct DerivedA * this, int parameter );
Eine Methode, die zur Basisklasse gehört, sieht entsprechend so aus:

Code: Alles auswählen

void MethodForBase( struct Base * this, int parameter );
Wenn Dich nun am ObjektTYP orientieren möchtest - es geht nämlich fast nie um das Objekt - so musst Du als erstes wissen, um welches Objekttyp es sich handelt. Das ist hier im Base-Objekt in 'id' gespeichert.
Du kannst in der Basis-Methode also hingehen und ein switch machen:

Code: Alles auswählen

void MethodForBase( struct Base * this, int parameter )
{
  switch( this->id )
  {
    case 1: /* I am a DerivedA */ break;
    case 2: /* I am a DerivedB */ break;
    default: /* I am abstract */ break;
  }
}
So wurde das früher auch regelmäßig gemacht. Das ganze ist natürlich fehleranfällig, denn wird ein neuer Objekttyp erzeugt, gehen die Probleme los. Sobald man irgendwo vergessen hat, das Switch zu erweitern, fliegt einem das Programm genau da um die Ohren: irgendwo eben...

Also schauen wir uns eine aufwendigere, aber interessantere Methode an, wie es auch (in der Regel - es ist nicht vorgeschrieben) in C++ gehandhabt wird. Wenn man ObjektTYP-orientiert programmieren möchte, so gelten für alle Objekte eines Typs die gleichen Methoden. Da wären zum einen die statischen Methoden, die für alle Objekte gelten - auch der abgeleiteten, bzw. Basistypen. Diese statischen Methoden können direkt und ohne Nachfrage angesprungen werden.
Die Methoden, die vom Objekttyp abhängig sind hingegen müssen erst in Abhängigkeit zum Objekttyp herausgesucht werden. Diese Methoden werden in C++ als "virtual" gekennzeichnet. Alle virtuellen Methoden werden in einer "Virtual Table" gesammelt. Für jeden Objekttyp existiert nun eine eigenstänige VTable, in der alle Adressen der erreichbaren virtuellen Funktionen stehen.
Das möchte ich mal herausheben: 'class' hat nicht OOP zu tun, DataHiding (public, protected, private) hat nicht mit OOP zu tun. Der Punkt, ab dem OOP einsetzt ist, wenn 'virtual' ins Spiel kommt. Ansonsten hat das nichts mit OOP zu tun (oder ist irgendwie selbst selbstgestrickt).

Der Zeiger für die VTable ersetzt damit die id und man braucht in C also zwei Strukturen pro Objekttyp:

Code: Alles auswählen

struct DataTypeDescription
{
  char const * ObjectTypeName;
}

struct VTable_Base
{
  struct DataTypeDescription base;
  void (*MethodForBase)( struct Base * this, int parameter );
};

struct Base
{
  struct VTable_Base * vTable;
  int BaseValue;
};

struct DerivedA
{
  struct Base * myBase;
  int ValueA;
};
struct DerivedA_VTable
{
  struct DataTypeDescription base;
  void (*MethodForBase)( struct Base * this, int parameter );
  void (*MethodForA)( struct DerivedA * this, int parameter );
}

struct DerivedB
{
  struct Base * myBase;
  int ValueB;
};
struct DerivedB_VTable
{
  struct DataTypeDescription base;
  void (*MethodForBase)( struct Base * this, int parameter );
  void (*MethodForB)( struct DerivedA * this, int parameter );
}
Im obigen Beispiel gibt es eine virtuelle Methode "MethodForBase". DerivedA und DerivedB fügen zusätzlich eigene virtuellen Methoden in ihre VTables hinzu.

Stellen wir uns nun eine Funktion vor, die eine virtualle Funktion in C aufrufen möchte:

Code: Alles auswählen

void func( struct Base * b, int parameter )
{
  /* Aufruf der virtuellen Methode 'MethodForBase'

  b->vTable->MethodForBase( b, parameter );
}
Da DerivedA und DerivedB unterschiedliche virtuelle Tabellen haben, können sie auch zu unterschiedlichen Methoden verzweigen. Der Funktionsaufruf ist aufwendiger (->vTable muss zusätzlich durchgegangen werden), aber die Funktion, die am Ende gerufen wird, kann abhängig vom Objekttyp frei bestimmt werden.

----
Ein kleiner Exkurs zur "Objektorientierten Programmierung". Wenn Funktionen wirklich von Objekt abhängen und nicht nur vom Typ, dann muss der Funktionszeiger direkt im Objekt sitzen und kann nicht für alle Objekte eines Typs in eine vTable ausgelagert werden.
So kann dann für jedes Objekt festgelegt werden, welche Funktion verwendet werden soll.

Code: Alles auswählen

int add( int a, int b ) { return a+b; }
int mul( int a, int b ) { return a*b; }

struct Operator
{
  int a, b;
  int (*operation)(int a, int b);
}

int doOperation( struct Operator * op )
{
  return op->operation( op->a, op->b );
}

int main(void)
{
  Operator opA, opB;
  opA = new Operator();
  opA->a = 1;
  opA->b = 2;
  opA->operation = add;
  
  opB = new Operator();
  opB->a = 1;
  opB->b = 2;
  opB->operation = mul;
}
Das wäre echte objektorientierte Programmierung...

------

Alle Listings sind ungeprüft...
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Objektorientiert Programmieren in C

Beitrag von Dirty Oerti » Mi Dez 17, 2008 11:12 pm

Danke :)

*Sich das jetzt noch ein paar mal durchles, um sicher zu sein, alles verstanden zu haben*

Hauptsächlich hab ich das zur Beantwortung einer Frage (Unterschied C <-> C++) gebraucht. Interessant ist es aber :)
Im Prinzip wird aus dem C++ Code ja damit auch nichts anderes generiert als aus diesem (doch etwas umfangreicheren) C Code, oder?

MfG
Daniel

*edit* Ein Nachtrag.... das Absenden DIESES Beitrags dauerte ca 30 Sekunden.... ?! */edit*
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Objektorientiert Programmieren in C

Beitrag von Xin » Do Dez 18, 2008 12:22 am

Dirty Oerti hat geschrieben:Danke :)

*Sich das jetzt noch ein paar mal durchles, um sicher zu sein, alles verstanden zu haben*

Hauptsächlich hab ich das zur Beantwortung einer Frage (Unterschied C <-> C++) gebraucht. Interessant ist es aber :)
Im Prinzip wird aus dem C++ Code ja damit auch nichts anderes generiert als aus diesem (doch etwas umfangreicheren) C Code, oder?
In der Regel nicht - wie gesagt - es gibt keine Vorschrift, wie man OOP implementiert, aber eine bessere Variante ist mir nicht bekannt.
Du kannst in C alles ausdrücken, was Du mit C++ programmieren kannst.
Allerdings sind Templates, also die Code-Generierung, in C eher unschön. Aber Konzepte, wie OOP sind natürlich alle umsetzbar.
Dirty Oerti hat geschrieben:*edit* Ein Nachtrag.... das Absenden DIESES Beitrags dauerte ca 30 Sekunden.... ?! */edit*
Heftig... wenn das so bleibt, werden wir auf kurz oder lang umziehen. :-/
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Objektorientiert Programmieren in C

Beitrag von cloidnerux » Sa Dez 20, 2008 7:15 pm

Sieht nach einer netten Spielerei aus,
aber für Praxistauglich halte ich das nicht.
So wie es aussieht, hat man keine möglichkeit dynamisch Objekte zu erzeugen und wieder zu löschen.
Auch Dinge wie Überladungen, Vererbung und Namensräume, die man von C++ gewohnt ist, sind unter dieser C Alternative nicht vorhanden.

Wenn man das sieht, dann ist mir auch bewusst, warum man C++ so ist wie es heute ist.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Objektorientiert Programmieren in C

Beitrag von Xin » So Dez 21, 2008 11:17 am

cloidnerux hat geschrieben:Sieht nach einer netten Spielerei aus,
aber für Praxistauglich halte ich das nicht.
Es ist praxistauglich, es wird auch verwendet, aber C++ ist angenehmer.
cloidnerux hat geschrieben:So wie es aussieht, hat man keine möglichkeit dynamisch Objekte zu erzeugen und wieder zu löschen.
Natürlich, man muss sich den Konstruktur nur selbst schreiben.
cloidnerux hat geschrieben:Auch Dinge wie Überladungen, Vererbung und Namensräume, die man von C++ gewohnt ist, sind unter dieser C Alternative nicht vorhanden.
Vererbung habe ich beschrieben, Überladungen sind für OOP nicht erforderlich und Namensräume werden durch Prefixe "emuliert".
cloidnerux hat geschrieben:Wenn man das sieht, dann ist mir auch bewusst, warum man C++ so ist wie es heute ist.
Natürlich, da ist vieles eingeflossen, was man durch die Programmierung von ältern Sprachen gelernt hat. Eben eine Weiterentwicklung.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Antworten