Strukturvererbung in C

Lesezeit: 10 Minuten

Kann ich eine Struktur in C erben? Wenn ja, wie?

  • In C gibt es keine Vererbung

    – Ed S.

    11. Juli 2009 um 18:30 Uhr

  • … Es sei denn, Sie implementieren es.

    – Philipp

    20. März 2013 um 15:28 Uhr

Benutzeravatar von Daniel Earwicker
Daniel Ohrwicker

Am nächsten kommt Ihnen die ziemlich gebräuchliche Redewendung:

typedef struct
{
    // base members

} Base;

typedef struct
{
    Base base;

    // derived members

} Derived;

Wie Derived beginnt mit einer Kopie von Basedu kannst das:

Base *b = (Base *)d;

Wo d ist eine Instanz von Derived. Sie sind also irgendwie polymorph. Aber virtuelle Methoden zu haben, ist eine weitere Herausforderung – dazu müssten Sie das Äquivalent eines vtable-Zeigers haben Basedie Funktionszeiger auf Funktionen enthalten, die akzeptieren Base als ihr erstes Argument (das Sie benennen könnten this).

An diesem Punkt können Sie auch C++ verwenden!

  • Nun, das setzt voraus, dass ein C++-Compiler für Ihre Plattform verfügbar ist!

    anon

    13. Juli 2009 um 1:22 Uhr

  • Wenn ein C-Compiler verfügbar ist, dann auch ein C++-Compiler – verwenden Sie einfach einen, der C als Ausgabe erzeugt.

    – Daniel Earwicker

    13. Juli 2009 um 6:29 Uhr

  • Puh… du hast mein Leben gerettet. Normalerweise programmiere ich in Java, und als ich mit dem Code konfrontiert wurde, der dem ähnelt, den Sie gepostet haben, dachte ich, es sei eine Komposition, und war höllisch verwirrt, als sie ihn gecastet haben.

    – Surya Wijaya Madjid

    11. September 2012 um 11:57 Uhr

  • Sie werden Anwendungen davon in komplexen realen Projekten (wie Git) sehen. Sehen log-tree.c. struct-Tag “erbt” von struct-Objekt

    – Albfan

    6. April 2013 um 23:36 Uhr


  • Entschuldigung, wie ist das? Base *b = (Base *)d; möglich. Einer ist ein Derived* und der andere ist a Base*. Seit Derived mehr Mitglieder haben würde, sind die Zeiger anders. Wie kannst du diese Besetzung machen?

    – Doga Oruk

    10. September 2020 um 12:35 Uhr

C hat im Gegensatz zu C++ kein explizites Vererbungskonzept. Sie können eine Struktur jedoch in einer anderen Struktur wiederverwenden:

typedef struct {
    char name[NAMESIZE];
    char sex;
} Person;

typedef struct {
    Person person;
    char job[JOBSIZE];
} Employee;

typedef struct {
    Person person;
    char booktitle[TITLESIZE];
} LiteraryCharacter;

  • Soweit ich weiß, können Sie in C++ auch ein Struktur-/Klassenmitglied in einem anderen haben.

    – Tyler Millican

    11. Juli 2009 um 18:36 Uhr

  • C sagt, dass vor dem ersten Mitglied einer Struktur keine Auffüllung erscheint. Sie können also tatsächlich (und dürfen) LiteraryCharacter* in Person* umwandeln und es als Person behandeln. +1

    – Johannes Schaub – litb

    12. Juli 2009 um 1:06 Uhr

  • @JohannesSchaub-litb dein Kommentar war eine bessere Erklärung als die Antwort selbst 🙂

    – Greg

    15. Februar 2012 um 11:49 Uhr

  • Es ist wichtig zu beachten, dass Sie diese Typen nur als Referenz übergeben dürfen. Sie können sie nicht in ein Personenobjekt kopieren, da sie sonst gespleißt werden.

    – Kevin Cox

    16. März 2014 um 17:35 Uhr

Ich mag und verwendet die Idee von Typsichere Vererbung in C.

Zum Beispiel:

struct Animal
{
    int weight;
};

struct Felidae
{
    union {
      struct Animal animal;
    } base;
    int furLength;
};

struct Leopard
{
    union {
      struct Animal animal;
      struct Felidae felidae;
    } base;

    int dotCounter;
};

Verwendungszweck:

struct Leopard leopard;
leopard.base.animal.weight = 44;
leopard.base.felidae.furLength = 2;
leopard.dotCounter = 99;

  • Daran habe ich nie gedacht. Und wenn man die Gewerkschaft anonym macht, ist das ganz ordentlich. Der Nachteil ist jedoch, dass Sie alle Eltern auflisten müssen, um verschachtelte Variablen zu vermeiden.

    – Kevin Cox

    16. März 2014 um 17:34 Uhr

  • Interessanter Ansatz. Allerdings schon beim Tippen leopard.basewird der ganze Punkt der Vererbung / Polymorphie eliminiert.

    – Machtsklave

    9. April 2015 um 9:21 Uhr

  • Bekommen Sie hier kein Problem mit der Vererbung von Diamanten? leopard.base.felidae.base.animal.weight und leopard.base.animal.weight?

    – Alexander Torstling

    15. Februar 2016 um 23:01 Uhr

  • @Alexander Torstling nein, wirst du nicht. leopard.base.felidae.base.animal.weight ist nur ein anderer Name für leopard.base.animal.weight – es ist dasselbe an derselben Stelle in der Erinnerung.

    – Martin

    21. Februar 2016 um 21:30 Uhr

  • Das sieht toll aus. Vielen Dank.

    – PSkočik

    15. Dezember 2016 um 21:16 Uhr

Wenn Ihr Compiler anonyme Strukturen unterstützt, können Sie Folgendes tun:

typedef struct Base
{
    // base members
} Base_t;

typedef struct
{
   struct Base;  //anonymous struct

   // derived members

} Derived_t;

Auf diese Weise kann direkt auf Basisstrukturmitglieder zugegriffen werden, was angenehmer ist.

Wenn Sie etwas gcc-Magie verwenden möchten (von der ich annehme, dass sie mit dem C-Compiler von Microsoft funktionieren würde), können Sie Folgendes tun:


struct A
{
   int member1;
};

struct B
{
   struct A;
   int member2;
}

Mit gcc können Sie dies mit -fms-extensions kompilieren (Erlaubt unbenannte Strukturmitglieder, wie es der Microsoft-Compiler tut). Dies ähnelt der Lösung von Daniel Earwicker, außer dass Sie damit auf memeber1 auf einer struct B-Instanz zugreifen können. dh B.member1 anstelle von BAmember1.

Dies ist wahrscheinlich nicht der portabelste Ansatz und funktioniert nicht, wenn Sie einen C++-Compiler verwenden (unterschiedliche Sprachsemantik bedeutet, dass Struktur A neu deklariert/definiert wird, anstatt sie zu instanziieren).

Wenn Sie jedoch nur im gcc/C-Land leben, wird es funktionieren und genau das tun, was Sie wollen.

  • Ist diese Zusammensetzung nicht?

    – Gipfel Gera

    20. September 2013 um 20:08 Uhr

  • Nein, es handelt sich um eine ordentliche Erbschaft. Angenommen, Sie haben eine Struktur vom Typ struct B mit dem Namen b, b.member1 wird kompiliert und funktioniert wie erwartet. Die Zusammensetzung wäre so etwas wie b.base.member1. GCC führt diese Magie für Sie durch. In diesem Fall hat es tatsächlich die Definition von struct B als zwei ganze Zahlen.

    – Matt

    21. September 2013 um 1:11 Uhr

  • Geht das nur in C, nicht in C++? Wenn nein, dann besuchen Sie uns bitte Dies.

    – Gipfel Gera

    21. September 2013 um 8:53 Uhr


  • Es ist nur C. Die Syntax ist in C++ illegal. Obwohl C++ genau wie Klassen eine ordnungsgemäße Vererbung von Strukturen hat.

    – Matt

    21. September 2013 um 12:55 Uhr

  • Jetzt fühle ich mich viel besser!

    – Gipfel Gera

    21. September 2013 um 15:44 Uhr


Dies funktioniert beim Kompilieren mit -fms-extensions

Diagrammbild

Haupt c

#include "AbstractProduct.h"
#include "Book.h"
#include "Product.h"
#include "TravelGuide.h"

/***********************/

int main() {

    Product p = Product_new();  
    p.set_id(&p, 2);
    p.set_name(&p, "name2");
    p.set_description(&p, "description2");
    p.set_price(&p, 2000);  
    p.display(&p);

    TravelGuide tg = TravelGuide_new(); 
    tg.set_id(&tg, 1);
    tg.set_name(&tg, "name1");
    tg.set_description(&tg, "description1");        
    tg.set_price(&tg, 1000);
    tg.set_isbn(&tg, "isbn1");
    tg.set_author(&tg, "author1");
    tg.set_title(&tg, "title1");
    tg.set_country(&tg, "country1");
    tg.display(&tg);

}

AbstractProduct.c

#include "AbstractProduct.h"

/*-------------------------------*/

static void set_id(AbstractProduct *this, int id) {
    this->id = id;
}

/*-------------------------------*/

static void set_name(AbstractProduct *this, char *name) {
    strcpy(this->name, name);
}

/*-------------------------------*/

static void set_description(AbstractProduct *this, char *description) {
    strcpy(this->description, description);
}

/*-------------------------------*/

static int get_id(AbstractProduct *this) {
    return this->id;    
}

/*-------------------------------*/

static char *get_name(AbstractProduct *this) {
    return this->name;  
}

/*-------------------------------*/

static char *get_description(AbstractProduct *this) {
    return this->description;   
}

/*-------------------------------*/

static void display(AbstractProduct *this) {

    printf("-AbstractProduct- \n"); 
    printf("id: %d\n", this->get_id(this)); 
    printf("name: %s\n", this->get_name(this)); 
    printf("description: %s\n", this->get_description(this));   
    printf("\n");
}

/*-------------------------------*/

void AbstractProduct_init(AbstractProduct *obj) {

    obj->set_id = set_id;
    obj->set_name = set_name;
    obj->set_description = set_description; 
    obj->get_id = get_id;
    obj->get_name = get_name;
    obj->get_description = get_description;
    obj->display = display;

}

/*-------------------------------*/

AbstractProduct AbstractProduct_new() {

    AbstractProduct aux;
    AbstractProduct_init(&aux);
    return aux;
}

AbstractProduct.h

#ifndef AbstractProduct_H
#define AbstractProduct_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/***********************/

typedef struct AbstractProduct{

    int id;
    char name[1000];
    char description[1000];

    void (*set_id)();
    void (*set_name)();
    void (*set_description)();  
    int (*get_id)();    
    char *(*get_name)();    
    char *(*get_description)(); 
    void (*display)();  

} AbstractProduct;

AbstractProduct AbstractProduct_new();
void AbstractProduct_init(AbstractProduct *obj);

#endif

Buch.c

#include "Book.h"

/*-------------------------------*/

static void set_isbn(Book *this, char *isbn) {
    strcpy(this->isbn, isbn);
}

/*-------------------------------*/

static void set_author(Book *this, char *author) {
    strcpy(this->author, author);
}

/*-------------------------------*/

static void set_title(Book *this, char *title) {
    strcpy(this->title, title);
}

/*-------------------------------*/

static char *get_isbn(Book *this) {
    return this->isbn;  
}

/*-------------------------------*/

static char *get_author(Book *this) {
    return this->author;    
}

/*-------------------------------*/

static char *get_title(Book *this) {
    return this->title; 
}

/*-------------------------------*/

static void display(Book *this) {

    Product p = Product_new();
    p.display(this);    

    printf("-Book- \n");
    printf("isbn: %s\n", this->get_isbn(this)); 
    printf("author: %s\n", this->get_author(this)); 
    printf("title: %s\n", this->get_title(this));   
    printf("\n");
}

/*-------------------------------*/

void Book_init(Book *obj) {

    Product_init((Product*)obj);

    obj->set_isbn = set_isbn;
    obj->set_author = set_author;
    obj->set_title = set_title; 
    obj->get_isbn = get_isbn;
    obj->get_author = get_author;
    obj->get_title = get_title; 
    obj->display = display;
}
/*-------------------------------*/

Book Book_new() {

    Book aux;   
    Book_init(&aux);
    return aux;
}

Buch.h

#ifndef Book_H
#define Book_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "Product.h"

/***********************/

typedef struct Book{

    Product;
    char isbn[1000];
    char author[1000];
    char title[1000];

    void (*set_isbn)();
    void (*set_author)();
    void (*set_title)();    

    char *(*get_isbn)();
    char *(*get_author)();
    char *(*get_title)();   
    // void (*display)();   


} Book;

Book Book_new();
void Book_init(Book *obj);

#endif

Produkt.c

#include "Product.h"

/*-------------------------------*/

static void set_price(Product *this, double price) {
    this->price = price;
}

/*-------------------------------*/

static double get_price(Product *this) {
    return this->price; 
}

/*-------------------------------*/

static void display(Product *this) {

    AbstractProduct p = AbstractProduct_new();
    p.display(this);    

    printf("-Product- \n"); 
    printf("price: %f\n", this->get_price(this));   
    printf("\n");
}

/*-------------------------------*/

void Product_init(Product *obj) {

    AbstractProduct_init((AbstractProduct*)obj);

    obj->set_price = set_price;
    obj->get_price = get_price; 
    obj->display = display;

}

/*-------------------------------*/

Product Product_new() {

    Product aux;    
    Product_init(&aux);
    return aux;
}

Produkt.h

#ifndef Product_H
#define Product_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "AbstractProduct.h"

/***********************/

typedef struct Product{

    AbstractProduct;
    double price;

    void (*set_price)();
    double (*get_price)();  
    // void (*display)();   

} Product;

Product Product_new();
void Product_init(Product *obj);

#endif

TravelGuide.c

#include "TravelGuide.h"

/*-------------------------------*/

static void set_country(TravelGuide *this, char *country) {
    strcpy(this->country, country);
}

/*-------------------------------*/

static char *get_country(TravelGuide *this) {
    return this->country;   
}

/*-------------------------------*/

static void display(TravelGuide *this) {

    Book b = Book_new();
    b.display(this);

    printf("-TravelGuide- \n"); 
    printf("country: %s\n", this->get_country(this));   
    printf("\n");
}

/*-------------------------------*/

void TravelGuide_init(TravelGuide *obj) {

    Book_init((Book*)obj);
    obj->set_country = set_country;
    obj->get_country = get_country;
    obj->f = obj->display;
    obj->display = display;

}

/*-------------------------------*/

TravelGuide TravelGuide_new() {

    TravelGuide aux;
    TravelGuide_init(&aux);
    return aux;
}

TravelGuide.h

#ifndef TravelGuide_H
#define TravelGuide_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "Book.h"

/***********************/

typedef struct TravelGuide{

    Book;
    char country[1000];
    void (*f)();

    void (*set_country)();
    char *(*get_country)();
    // void *(*display)();

} TravelGuide;

TravelGuide TravelGuide_new();
void TravelGuide_init(TravelGuide *obj);

#endif

Makefile

.PHONY: clean
define ANNOUNCE_BODY

    ***********************************************
    ************          start make **************
    ***********************************************
endef

all:
    $(info $(ANNOUNCE_BODY))    

    clear;
    if [ -f binary/main ]; then rm binary/main; fi;

# compiler 

    gcc $(INC) -c -fms-extensions main.c -o binary/main.o
    gcc $(INC) -c -fms-extensions AbstractProduct.c -o binary/AbstractProduct.o
    gcc $(INC) -c -fms-extensions Product.c -o binary/Product.o
    gcc $(INC) -c -fms-extensions Book.c -o binary/Book.o
    gcc $(INC) -c -fms-extensions TravelGuide.c -o binary/TravelGuide.o

# linker    

    gcc binary/main.o \
        binary/AbstractProduct.o \
        binary/Product.o \
        binary/Book.o \
        binary/TravelGuide.o \
        -o \
        binary/main

  • Ist diese Zusammensetzung nicht?

    – Gipfel Gera

    20. September 2013 um 20:08 Uhr

  • Nein, es handelt sich um eine ordentliche Erbschaft. Angenommen, Sie haben eine Struktur vom Typ struct B mit dem Namen b, b.member1 wird kompiliert und funktioniert wie erwartet. Die Zusammensetzung wäre so etwas wie b.base.member1. GCC führt diese Magie für Sie durch. In diesem Fall hat es tatsächlich die Definition von struct B als zwei ganze Zahlen.

    – Matt

    21. September 2013 um 1:11 Uhr

  • Geht das nur in C, nicht in C++? Wenn nein, dann besuchen Sie uns bitte Dies.

    – Gipfel Gera

    21. September 2013 um 8:53 Uhr


  • Es ist nur C. Die Syntax ist in C++ illegal. Obwohl C++ genau wie Klassen eine ordnungsgemäße Vererbung von Strukturen hat.

    – Matt

    21. September 2013 um 12:55 Uhr

  • Jetzt fühle ich mich viel besser!

    – Gipfel Gera

    21. September 2013 um 15:44 Uhr


Benutzeravatar von Ziezi
Ziezi

Sie können das oben genannte tun

typedef struct
{
    // base members

} Base;

typedef struct
{
    Base base;

    // derived members

} Derived;

Aber wenn Sie das Casting von Zeigern vermeiden möchten, können Sie Zeiger auf a verwenden union von Base und Derived.

1417980cookie-checkStrukturvererbung in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy