4

私はオブジェクト指向の機能を C で動作させる必要がある立場にあり、特に継承が必要です。幸いなことに、スタック オーバーフローに関する参考文献がいくつかあります。特に、このSemi-inheritance in C: How does this snippet work? そして、このC のオブジェクト指向。アイデアは、次のように、派生クラス内に基本クラスのインスタンスを含め、それを型キャストすることです。

struct base {
    int x;
    int y;
};

struct derived {
    struct base super;
    int z;
};

struct derived d;
d.super.x = 1;
d.super.y = 2;
d.z = 3;
struct base b = (struct base *)&d;

これは素晴らしいことですが、継承ツリーが深いと扱いにくくなります。約 5 ~ 6 個の「クラス」のチェーンが必要になるため、常に「derived.super.super.super.super.super.super」と入力したくはありません。 . 私が望んでいたのは、次のように、最初の n 要素の構造体に型キャストできることでした。

struct base {
    int x;
    int y;
};

struct derived {
    int x;
    int y;
    int z;
};

struct derived d;
d.x = 1;
d.y = 2;
d.z = 3;
struct base b = (struct base *)&d;

Visual Studio 2012 に付属の C コンパイラでこれをテストしましたが、動作しますが、C 標準が実際にそれを保証しているかどうかはわかりません。これが大丈夫かどうかを確実に知っている人はいますか?そのような基本的なレベルで壊れていることを発見するためだけに、山ほどのコードを書きたくありません。

4

3 に答える 3

3

ここで説明するのは、完全に移植可能であり、言語の設計によって機能することが本質的に保証されていた構造です。仕事。C89 では、構造体へのポインターではなく、共用体の Common Initial Sequence ルールを指定しました。

struct s1 {int x; int y; ... other stuff... };
struct s2 {int x; int y; ... other stuff... };
union u { struct s1 v1; struct s2 v2; };

または malloc されたオブジェクトのstruct s1*いずれかである外部オブジェクトへのを受け取ったコードは、 それがその型にアラインされていれば合法的に にキャストでき、結果のポインターを に合法的にキャストできます。またはメンバーを介して共用体にアクセスするのと同じでなければなりません。したがって、指定されたすべての規則をコンパイラが機能させる唯一の方法は、ある構造体型のポインターを別の型のポインターに変換し、そのポインターを使用して Common Initial Sequence のメンバーを検査することが機能すると言うことです。union u*union u*struct s2*struct s1*struct s2*v1v2

残念ながら、コンパイラの作成者は、CIS 規則は、基礎となるオブジェクトが共用体型を持つ場合にのみ適用可能であると述べています。構造体へのポインターは、CIS を検査する目的で同じように扱われるべきであるstruct s1*ことをコンパイラーに知らせます)。可能性。したがって、上記の宣言が表示されたとしても、gcc は aから CIS のメンバーにアクセスするために a が使用されることはないと想定します。struct s2*union ustruct s1*struct s2*

于 2016-09-02T21:34:42.963 に答える
-1

ポインターを使用することで、階層内の任意のレベルにある基本クラスへの参照をいつでも作成できます。また、継承構造の何らかの記述を使用すると、ビルド ステップとして必要な「クラス定義」とファクトリ関数の両方を生成できます。

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

struct foo_class {
  int a;
  int b;
};

struct bar_class {
  struct foo_class foo;
  struct foo_class* base;

  int c;
  int d;
};

struct gazonk_class {
  struct bar_class bar;
  struct bar_class* base;

  struct foo_class* Foo;

  int e;
  int f;
};

struct gazonk_class* gazonk_factory() {
  struct gazonk_class* new_instance = malloc(sizeof(struct gazonk_class));

  new_instance->bar.base = &new_instance->bar.foo;
  new_instance->base = &new_instance->bar;
  new_instance->Foo = &new_instance->bar.foo;

  return new_instance;
}

int main(int argc, char* argv[]) {
  struct gazonk_class* object = gazonk_factory();

  object->Foo->a = 1;
  object->Foo->b = 2;

  object->base->c = 3;
  object->base->d = 4;

  object->e = 5;
  object->f = 6;

  fprintf(stdout, "%d %d %d %d %d %d\n",
      object->base->base->a,
      object->base->base->b,
      object->base->c,
      object->base->d,
      object->e,
      object->f);

  return 0;
}

この例では、baseポインタを使用して戻るか、基本クラスを直接参照できます。

于 2013-09-25T06:10:47.777 に答える
-1

astructのアドレスは、保証された最初の要素のアドレスです。

于 2013-09-25T01:09:12.310 に答える