Development Tip

C의 구조 상속

yourdevel 2020. 11. 29. 12:22
반응형

C의 구조 상속


C에서 구조를 상속받을 수 있습니까? 그렇다면 어떻게?


가장 가까운 것은 매우 일반적인 관용구입니다.

typedef struct
{
    // base members

} Base;

typedef struct
{
    Base base;

    // derived members

} Derived;

Derived의 복사본으로 시작하면 다음과 같이 Base할 수 있습니다.

Base *b = (Base *)d;

d의 인스턴스는 어디에 있습니까 Derived? 그래서 그들은 일종의 다형성입니다. 그러나 가상 메서드를 갖는 것은 또 다른 도전입니다. 그렇게하려면 첫 번째 인수로 Base허용하는 함수에 대한 함수 포인터를 포함하는 에서 vtable 포인터에 해당하는 것이 있어야합니다 Base(이름을 지정할 수 있음 this).

어느 시점에서 C ++를 사용하는 것이 좋습니다!


C에는 C ++와 달리 명시적인 상속 개념이 없습니다. 그러나 다른 구조에서 구조를 재사용 할 수 있습니다.

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

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

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

나는 C에서 Typesafe 상속 의 아이디어를 좋아하고 사용했습니다 .

예를 들면 :

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

용법:

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

gcc 마법을 사용하고 싶다면 (Microsoft의 C 컴파일러에서 작동한다고 가정합니다) 다음과 같이 할 수 있습니다.


struct A
{
   int member1;
};

struct B
{
   struct A;
   int member2;
}

gcc를 사용하면 -fms-extensions로 컴파일 할 수 있습니다 (Microsoft 컴파일러처럼 이름이 지정되지 않은 구조체 멤버 허용). 이것은 struct B 인스턴스에서 memeber1에 액세스 할 수 있다는 점을 제외하면 Daniel Earwicker가 제공 한 솔루션과 유사합니다. 즉, BAmember1 대신 B.member1.

이것은 아마도 가장 이식 가능한 접근 방식이 아니며 C ++ 컴파일러를 사용하는 경우 작동하지 않을 것입니다 (다른 언어 의미론은 인스턴스화하는 대신 구조체 A를 다시 선언 / 정의한다는 것을 의미합니다).

그러나 gcc / C 토지에 거주하는 경우에만 작동하고 원하는대로 정확하게 수행 할 수 있습니다.


컴파일러가 익명 ​​구조체를 지원하는 경우 다음을 수행 할 수 있습니다.

typedef struct Base
{
    // base members
} Base_t;

typedef struct
{
   struct Base;  //anonymous struct

   // derived members

} Derived_t;

이런 식으로 기본 stuct 멤버를 직접 액세스 할 수 있습니다.


위에서 언급 한 것을 할 수 있습니다.

typedef struct
{
    // base members

} Base;

typedef struct
{
    Base base;

    // derived members

} Derived;

그러나 포인터 캐스팅을 피하려면 unionof Base및에 대한 포인터를 사용할 수 있습니다 Derived.


이것은 -fms-extensions로 컴파일됩니다.

다이어그램 이미지

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

anon의 답변에 대한 약간의 변형 (및 기타 유사). 한 수준 깊은 상속의 경우 다음을 수행 할 수 있습니다.

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

typedef struct {
    BASEFIELDS;
} Person;

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

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

이렇게하면 Person에 대한 포인터를 수락하는 함수는 다른 답변과 마찬가지로 Employee 또는 Manager (캐스트 포함)에 대한 포인터를 수락하지만이 경우 초기화도 자연 스럽습니다.

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

vs

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

나는 이것이 몇몇 유명한 프로젝트가 그렇게하는 방법이라고 믿는다 (예 : libuv)

업데이트 : 또한 구조체와 공용체를 사용하는 libsdl 이벤트 구현에서 유사한 (동일하지는 않음) 개념의 좋은 예가 있습니다.


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


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


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


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

참고URL : https://stackoverflow.com/questions/1114349/struct-inheritance-in-c

반응형