構造体はなぜ継承をサポートしないのでしょうか? 質問する

構造体はなぜ継承をサポートしないのでしょうか? 質問する

.NETの構造体は継承をサポートしていないことは知っていますが、正確にはわかりません。なぜこのように制限されています。

構造体が他の構造体から継承できない技術的な理由は何ですか?

ベストアンサー1

値型が継承をサポートできない理由は、配列のためです。

問題は、パフォーマンスと GC の理由から、値型の配列が「インライン」で保存されることです。たとえば、 が参照型のnew FooType[10] {...}場合FooType、マネージド ヒープには 11 個のオブジェクトが作成されます (配列用に 1 つ、各型インスタンス用に 10 個)。 がFooType値型の場合、マネージド ヒープには配列自体のインスタンスが 1 つだけ作成されます (各配列値は配列とともに「インライン」で保存されるため)。

さて、値型による継承があったとします。配列の上記の「インラインストレージ」動作と組み合わせると、次のような悪い事態が発生します。C++で

次の疑似 C# コードを検討してください。

struct Base
{
    public int A;
}

struct Derived : Base
{
    public int B;
}

void Square(Base[] values)
{
  for (int i = 0; i < values.Length; ++i)
      values [i].A *= 2;
}

Derived[] v = new Derived[2];
Square (v);

通常の変換ルールでは、 aDerived[]は a に変換可能ですBase[](良くも悪くも)。そのため、上記の例で s/struct/class/g を実行すると、問題なく期待どおりにコンパイルおよび実行されます。ただし、Baseと がDerived値型であり、配列が値をインラインで格納する場合は、問題が発生します。

Square()は について何も知らないためDerived、ポインタ演算のみを使用して配列の各要素にアクセスし、定数 ( ) ずつ増分するため、問題が発生しますsizeof(A)。アセンブリは、おおよそ次のようになります。

for (int i = 0; i < values.Length; ++i)
{
    A* value = (A*) (((char*) values) + i * sizeof(A));
    value->A *= 2;
}

(はい、これはひどいアセンブリですが、ポイントは、派生型が使用されていることをまったく認識せずに、既知のコンパイル時定数で配列を増分することです。)

したがって、これが実際に起こった場合、メモリ破損の問題が発生します。具体的にはSquare()values[1].A*=2実は変更中values[0].B

デバッグしてみるそれ

おすすめ記事