jimit
jimit

Reputation:

Struct Inheritance in C

Can I inherit a structure in C? If yes, how?

Upvotes: 85

Views: 70891

Answers (12)

MighMoS
MighMoS

Reputation: 1254

You can do the above mentioned

typedef struct
{
    // base members

} Base;

typedef struct
{
    Base base;

    // derived members

} Derived;

But if you want to avoid pointer casting, you can use pointers to a union of Base and Derived.

Upvotes: 4

Daniel Earwicker
Daniel Earwicker

Reputation: 116654

The closest you can get is the fairly common idiom:

typedef struct
{
    // base members

} Base;

typedef struct
{
    Base base;

    // derived members

} Derived;

As Derived starts with a copy of Base, you can do this:

Base *b = (Base *)d;

Where d is an instance of Derived. So they are kind of polymorphic. But having virtual methods is another challenge - to do that, you'd need to have the equivalent of a vtable pointer in Base, containing function pointers to functions that accept Base as their first argument (which you could name this).

By which point, you may as well use C++!

Upvotes: 112

snobb
snobb

Reputation: 1064

A slight variation to the answer of anon (and others' similar). For one level deep inheritance one can do the following:

#define BASEFIELDS              \
    char name[NAMESIZE];        \
    char sex

typedef struct {
    BASEFIELDS;
} Person;

typedef struct {
    BASEFIELDS;
    char job[JOBSIZE];
} Employee;

typedef struct {
    BASEFIELDS;
    Employee *subordinate;
} Manager;

This way the functions accepting pointer to Person, will accept pointer to Employee or Manager (with casting), same as in other answers, but in this case the initialisation will be natural as well:

Employee e = {
    .name = "...";
    ...
};

vs

# as in anon's answer
Employee e = {
    .person.name = "...";
    ...
};

I believe this is how some popular projects do that (eg. libuv)

UPDATE: also there are some good examples of similar (but not the same) concept in libsdl events implementation using structs and unions.

Upvotes: 4

MoaLaiSkirulais
MoaLaiSkirulais

Reputation: 134

This works compiling with -fms-extensions

Diagram image

main.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

Book.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;
}

Book.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

Product.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;
}

Product.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

Upvotes: 4

Matt
Matt

Reputation: 1901

If you want to use some gcc magic (that I would assume would work with Microsoft's C compiler) you can do something like:


struct A
{
   int member1;
};

struct B
{
   struct A;
   int member2;
}

With gcc you can compile this with -fms-extensions (Allows for unnamed struct members like Microsofts compiler does). This is similar to the solution given by Daniel Earwicker except that it allows you to access memeber1 on a struct B instance. i.e B.member1 instead of B.A.member1.

This is probably not the most portable approach and will not work if using a C++ compiler (different language semantics mean that it is redeclaring/defining struct A instead of instantiating it).

If however you live in the gcc/C land only it will work and do exactly what you want.

Upvotes: 9

user836773
user836773

Reputation: 345

If your compiler supports anonymous structs, you can do this:

typedef struct Base
{
    // base members
} Base_t;

typedef struct
{
   struct Base;  //anonymous struct

   // derived members

} Derived_t;

This way, base stuct members can be acessed directly, which is nicer.

Upvotes: 11

Martin
Martin

Reputation: 10868

I like and used the idea of Typesafe inheritance in C.

For example:

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;
};

Usage:

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

Upvotes: 42

Macarse
Macarse

Reputation: 93133

No, you cant. imo the best approach to OOP in C is using ADT.

Upvotes: -4

anon
anon

Reputation:

C has no explicit concept of inheritance, unlike C++. However, you can reuse a structure in another structure:

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

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

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

Upvotes: 49

luiscubal
luiscubal

Reputation: 25121

You can simulate it, but you can't really inherit.

Upvotes: -3

txwikinger
txwikinger

Reputation: 3034

C is not an object-oriented language and hence has no inheritance.

Upvotes: -3

JaredPar
JaredPar

Reputation: 754545

No you cannot. C does not support the concept of inheritance.

Upvotes: -6

Related Questions