Kann ich eine Struktur in C erben? Wenn ja, wie?
Strukturvererbung in C
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 Base
du 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 Base
die 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 einDerived*
und der andere ist aBase*
. SeitDerived
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.base
wird 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
undleopard.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ürleopard.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
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
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
.
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