2016-07-12 8 views
2

Angenommen, ich die folgende StrukturZugreifen auf Mitglieder in Struktur mit Member-Funktion?

struct Being{ 
    int canFly; 
    int (*printFlying)(); 
} 

Und ich will etwas tun, wie das folgende haben:

int main(){ 
    struct Being * flyingThing = new_flyingThing(); 
    struct Being * thingThatCantFly = new_Thing(); 

    flyingThing->printFlying(); /* "I'm flying!" */ 
    thingThatCantFly->printFlying(); /* "I can't fly!" */ 
} 

Es sieht aus wie ich die printFlying Funktion benötigen würde die canFly Variable zugreifen zu können, in die Struktur, aber ich weiß nicht, wie das geht, oder wenn das möglich ist.

Gibt es eine Möglichkeit, meinen Code zu tun, was ich will? Vielen Dank!!


Ich erklärte in den Kommentaren, warum diese Frage kein Duplikat des verknüpften ist.

+2

C ist nicht Java. Es scheint, dass Sie versuchen, OOP in C zu verwenden, für das es nicht vorgesehen ist. –

+1

Sie müssten 'printFlying 'einen Parameter geben, der Zeiger auf das Objekt in Frage –

+0

@ John3136 Ich habe bereits die Antworten in dieser Frage gelesen, und sie beantworten meine Frage nicht: Die meisten von ihnen verwenden Dinge wie' Funktion (struct ...) 'um dies zu tun, während die Funktion keine Parameter annehmen soll (' struct ... -> function() '). – csTroubled

Antwort

1

Die Funktion, auf die der Zeiger printFlying zeigt, kann nicht auf Elemente der enthaltenden Struktur struct Being zugreifen, es sei denn, es wird ein Parameter angegeben, der sich auf diese Struktur bezieht. (Oder es könnte die Struktur auf eine andere Art und Weise zuzugreifen, vielleicht über eine globale Variable, sondern ein Parameter ist der sauberste Weg.)

Betrachten wir zum Beispiel zwei Objekte vom Typ struct Being, die beide ihre printFlying Zeiger, der auf die gleiche Funktion. Es gibt keine Möglichkeit, dass die Funktion erkennen kann, mit welchem ​​der beiden Objekte sie verknüpft ist - weil sie keinem der beiden Objekte zugeordnet ist.

C++ - Memberfunktionen können das tun, weil sie einen impliziten Zeigerparameter erhalten, auf den innerhalb der Funktion über das Schlüsselwort this verwiesen wird. C hat keine solche Funktion.

Sie könnten wahrscheinlich ein Makro erstellen, das etwas Ähnliches tut, aber ich bezweifle, dass es die Mühe wert wäre.

Haben Sie überlegt, nur C++ zu verwenden?

2

C ist keine objektorientierte Sprache, daher gibt es für einen Funktionsmember keine automatische Möglichkeit zu wissen, über welche Struktur er aufgerufen wurde.

Da jede Struktur über einen eigenen Funktionszeiger verfügt, können Sie das gewünschte Ergebnis erhalten, indem sie auf verschiedene Funktionen verweisen, die die entsprechende Nachricht drucken, anstatt sie vom -Mitglied abzurufen.

int print_flying_thing() { 
    printf("I'm flying!\n"); 
} 
struct Being *new_flyingThing() { 
    struct Being *thing = malloc(sizeof(struct Being)); 
    thing->can_fly = 1; 
    thing->printFlying = print_flying_thing; 
    return thing; 
} 

int print_nonflying_thing() { 
    printf("I can't fly!\n"); 
} 
struct Being *new_Thing() { 
    struct Being *thing = malloc(sizeof(struct Being)); 
    thing->can_fly = 0; 
    thing->printFlying = print_nonflying_thing; 
    return thing; 
} 
+0

Sicher, aber die Funktionen können immer noch nicht auf Mitglieder der Struktur zugreifen. –

+0

@KeithThompson Das stimmt, aber in aller Fairness wollte ich das nur verwenden, um zu überprüfen, ob der Wert von 'canFly' wahr oder falsch war. – csTroubled

+0

Wenn Sie es zum Standard machen, dass das erste Argument einer beliebigen "oo" c-Struktur einen Zeiger auf sich selbst nimmt ('int (* printFlying) (Being *);' dann folgen Sie dem Prozess, dass Sie immer die Struktur übergeben, die Ihnen wichtig ist: 'thing-> printFlying (thing)' Dann kann man den Mitgliederzugriff etwas emulieren –

1

Für dieses spezielle Beispiel, was Sie wirklich wollen, scheinen die Fähigkeit, einen Funktionszeiger zu haben, die auf zwei verschiedene Funktionen verweist, ein Fliegen und ein zu implementieren, die nicht fliegen implementiert.

Also wäre der Ansatz, den ich betrachten würde, etwas wie das Folgende. Ich habe nicht versucht, diesen Code tatsächlich zu kompilieren, aber der Sinn dafür ist richtig.

Auch in Ihren Kommentaren haben Sie erwähnt, dass das Ändern des Funktionszeigers verhindert wird. Sie können etwas wie das Folgende tun, wo ein const der Strukturdefinition für den Funktionszeiger hinzugefügt wird und dann einen Klon der Struktur mit einem Cast verwendet.

Header-Datei flying.h Inhalt.

typedef struct _TAG_Being { 
    int (* const printFlying)(); 
} Being; 

Being * new_flyingThing(); 
Being * new_Thing(); 

Implementierung oder flying.c-Datei.

#include "flying.h" 

static int printFlyingThing() 
{ 
    printf (" I am a flying thing\n"); 
    return 0; 
} 

static int printThing() 
{ 
    printf (" I am a thing\n"); 
    return 1; 
} 

// use the same layout and members as Being above. 
typedef struct { 
    int (* printFlying)(); 
} BeingX; 

Being * new_flyingThing() 
{ 
    BeingX *p = malloc(sizeof(BeingX)); 
    p->printFlying = printFlyingThing; // use the flying thing function 

    { 
     Being *q = (Being *)p; 
     return q; 
    } 
} 

Being * new_Thing() 
{ 
    BeingX *p = malloc(sizeof(BeingX)); 
    p->printFlying = printThing;  // use the not flying thing function. 

    { 
     Being *q = (Being *)p; 
     return q; 
    } 
} 

Main oder mit C-Datei

#include "flying.h" 

int main(){ 
    Being * flyingThing = new_flyingThing(); 
    Being * thingThatCantFly = new_Thing(); 

    flyingThing->printFlying(); /* "I'm flying!" */ 
    thingThatCantFly->printFlying(); /* "I can't fly!" */ 
} 

Wenn Sie eine Notwendigkeit, die tatsächliche Being Objekt oder eine Variable in der printFlying() Funktion zuzugreifen, dann müssen Sie es als ein Argument zu übergeben.

Zum Beispiel:

typedef struct _TAG_Being { 
    int xx; 
    int (*printFlying)(struct _TAG_Being *p); 
} Being; 

Dann würden Sie so etwas wie benötigen:

Being * flyingThing = new_flyingThing(); 

flyingThing->printFlying(flyingThing); /* "I'm flying!" */ 
Verwandte Themen