web-dev-qa-db-ja.com

Cを使用して継承をモデル化するにはどうすればよいですか?

Cを使用して継承をモデル化することは可能ですか?どうやって?サンプルコードが役立ちます。

編集:データとメソッドの両方を継承したいと考えています。コンテナ船だけでは役に立ちません。代替可能性-基本クラスオブジェクトが機能する派生クラスオブジェクトを使用する-が必要です。

42
Agnel Kurian

このようにするのはとても簡単です:

struct parent {
    int  foo;
    char *bar;
};

struct child {
    struct parent base;
    int bar;
};

struct child derived;

derived.bar = 1;
derived.base.foo = 2;

ただし、MS拡張機能を使用する場合(GCCでは-fms-extensionsフラグ)ネストされた匿名のstructsを使用できます。

struct child {
    struct parent;    // anonymous nested struct
    int bar;
};

struct child derived;

derived.bar = 1;
derived.foo = 2;     // now it is flat
27
qrdl

Cは(ある程度)オブジェクト指向スタイルで間違いなく書くことができます。

カプセル化は、構造の定義を関連するヘッダーではなく.cファイルに保持することで実行できます。次に、外界はオブジェクトへのポインタを保持することでオブジェクトを処理し、オブジェクトの「メソッド」としてそのようなポインタを受け入れる関数を提供します。

ポリモーフィズムのような動作は、通常は「操作構造」内にグループ化された関数ポインターを使用して取得できます。これは、C++オブジェクトの「仮想メソッドテーブル」のようなものです(またはそれが呼び出されます)。 ops構造には、特定の「サブクラス」に固有の値を持つ定数など、他のものも含めることができます。 「親」構造は、汎用void*ポインターを介してops固有のデータへの参照を保持できます。もちろん、「サブクラス」は、複数レベルの継承に対してパターンを繰り返すことができます。

そのため、以下の例では、struct printerは抽象クラスに似ており、pr_ops構造体に入力し、pr_create()をラップするコンストラクター関数を提供することで「派生」できます。各サブタイプには、dataジェネリックポインターを介してstruct printerオブジェクトに「固定」される独自の構造があります。これは、fileprinterサブタイプによって示されます。 struct printer *参照としてコードの残りの部分に関係なく操作されるGUIまたはソケットベースのプリンターを想像できます。

printer.h:

struct pr_ops {
    void (*printline)(void *data, const char *line);
    void (*cleanup)(void *data);
};

struct printer *pr_create(const char *name, const struct output_ops *ops, void *data);
void pr_printline(struct printer *pr, const char *line);
void pr_delete(struct printer *pr);

printer.c:

#include "printer.h"
...

struct printer {
    char *name;
    struct pr_ops *ops;
    void *data;
}

/* constructor */
struct printer *pr_create(const char *name, const struct output_ops *ops, void *data)
{
    struct printer *p = malloc(sizeof *p);
    p->name = strdup(name);
    p->ops = ops;
    p->data = data;
}

void pr_printline(struct printer *p, const char *line)
{
    char *l = malloc(strlen(line) + strlen(p->name) + 3;
    sprintf(l, "%s: %s", p->name, line);
    p->ops->printline(p->data, l);
}

void pr_delete(struct printer *p)
{
    p->ops->cleanup(p->data);
    free(p);
}

最後に、fileprinter.c:

struct fileprinter {
    FILE *f;
    int doflush;
};

static void filepr_printline(void *data, const char *line)
{
    struct fileprinter *fp = data;
    fprintf(fp->f, "%s\n", line);
    if(fp->doflush) fflush(fp->f);
}

struct printer *filepr_create(const char *name, FILE *f, int doflush)
{
    static const struct ops = {
        filepr_printline,
        free,
    };

    struct *fp = malloc(sizeof *fp);
    fp->f = f;
    fp->doflush = doflush;
    return pr_create(name, &ops, fp);
}
11

はい、「型パニング」手法を使用して、Cで遺産をエミュレートできます。これは、派生クラス内の基本クラス(構造体)の宣言であり、派生クラスをベースとしてキャストします。

struct base_class {
  int x;
};

struct derived_class {
  struct base_class base;
  int y;
}

struct derived_class2 {
  struct base_class base;
  int z;
}
void test() {
  struct derived_class d;
  struct derived_class2 d2;

  d.base.x = 10;
  d.y = 20;

  printf("x=%i, y=%i\n", d.base.x, d.y);
}

ただし、プログラムで派生としてベースをキャストする場合は、派生構造の最初の位置でベースクラスを宣言する必要があります。

 struct base *b1, *b2;

 b1 = (struct base *)d;
 b2 = (struct base *)d2;

 b1->x=10;
 b2->x=20;
 printf("b1 x=%i, b2 x=%i\n", b1->x, b2->x);

このスニペットでは、基本クラスのみを使用できます。

私は自分のプロジェクトでこのテクニックを使用しています: oop4c

4
curif

少なくともある程度は可能であるべきです。

モデリングには正確に何が必要ですか?データまたはメソッドの継承?

Edit:これは私が見つけた短い記事です: http://fluff.info/blog/Arch/00000162.htm

2
rslite

C++の初期バージョンは主にCに変換されるプリプロセッサであったため、間違いなく可能です。

2
mhawke

私はCでオブジェクトシステムを使用しましたが、これは遅延バインドメソッドを使用し、リフレクションを使用したオブジェクト指向を可能にしました。

あなたはそれについて読むことができます こちら

2
Ryan Fox

このリンクは役に立つかもしれません-> link

基本的な例は次のようになります

 struct BaseStruct
{
  // some variable
}


struct DerivedStruct
{
  struct BaseStruct lw;
  // some more variable
};
1
malay
#include <stdio.h> 

///////Class Cobj
typedef struct Cobj{
    int x;
    void (*setptr)(char * s,int val);
    int (*getptr)(char * s);
} Cobj;

void set(char * s,int val)
{
    Cobj * y=(Cobj *)s;
    y->x=val;
}
int get(char * s){
    Cobj * y=(Cobj *)s;
    return y->x;
}
///////Class Cobj
Cobj s={12,set,get};
Cobj x;

void main(void){
    x=s;
    x.setptr((char*)&x,5);
    s.setptr((char*)&s,8);
    printf("%d %d %d",x.getptr((char*)&x),s.getptr((char*)&s) ,sizeof(Cobj));
}
1
Raks