2012-03-15 20 views
3

C++とC#の違いを理解するのに問題があります。C#vs C++ - 型、継承、vtable

まず、基本クラスに仮想関数が含まれている例があります。

class Base 
{ 
protected: 
    int super; 
public: 
    virtual int f() = 0; 
}; 

class Derived : public Base 
{ 
public: 
    int extraA; 
    int f(){ return 1; } 
}; 

int main() 
{ 
    Derived *d = new Derived(); 

    std::vector<Base*> v; 
    v.push_back(d); 

    for(int i=0; i < v.size() ;i++) 
    { 
      // Output "Derived" 
      std::cout << typeid(*v[i]).name() << std::endl; 
    } 

    return 0; 
} 

この出力は、期待どおりに「派生」です。

f()を削除しても機能しなくなりました。出力は「ベース」です。例:これの

class Base 
{ 
protected: 
    int super; 
}; 

class Derived : public Base 
{ 
public: 
    int extraA; 
}; 

int main() 
{ 
    Derived *d = new Derived(); 

    std::vector<Base*> v; 
    v.push_back(d); 

    for(int i=0;i<v.size();i++) 
    { 
      // Output "Base" 
      std::cout << typeid(*v[i]).name() << std::endl; 
    } 

    return 0; 
} 

私の理解では、仮想関数を持つことがvtableのを指すオブジェクトにvptrを追加するために、コンパイラを引き起こすこと、です。 vtableには正しい関数のアドレスが含まれています(Derived :: f()) - (オブジェクトの型情報と同様に)

ここで興味深いのはC#との比較です。ここで、「基本」と「派生」は、基本的に第二C++の例のように空のクラスです:

public static void Main() 
{ 
     Derived d = new Derived(); 
     IList<Base> v = new List<Base>(); 
     mList.Add(d); 

     for (int i = 0; i < v.Count; i++) 
     { 
      // Output: "Derived" 
      System.Console.WriteLine(v.ElementAt(i).GetType()); 
     } 
} 

私の質問は、このようにされる:Cの私の理解は正しい部品++で、どのようにC#が正しく識別するために管理していC++がないときのオブジェクトの型?

+1

この記事は、これがC#の背後でどのように実装されているかを理解するのに役立ちます。http://msdn.microsoft.com/en-us/magazine/cc163791.aspx - オブジェクトレイアウトに関するセクションを参照してください。 –

答えて

6

C++では、クラスにvirtualという関数がある場合にのみ実行時の多形性と型識別が可能になります。これは、共通の実装ではvptrがクラスに追加されていることを意味します(これはC++の "あなたはあなたが必要でないものを支払うことはありません ")。 (?と同様にオブジェクトの型情報)

しかし、それはクラスのvtableの最初のスロットにRTTIレコードへのポインタを格納するために一般的だ - と私は思いこれは、クラスが多型である場合にのみ標準がRTTIを動作させることを要求する理由の1つであると言います(ただし、通常はこれはすべてコンパイラに依存します)。

ちなみに、RTTは仮想ディスパッチが正しく機能するためには必要ありません。コンパイラが行うべき仮想関数を呼び出す場合は、ポインタをvtableの正しいスロットから取り出してcall ptrを実行する必要があります。 RTTIレコードは、dynamic_castのクラス階層をチェックし、typeidを介してオブジェクトのタイプについて明示的に尋ねるときにのみ使用されます。

C#では、すべてのクラスがデフォルトでポリモーフィックであり、リフレクションメタデータが関連付けられているため、多態性/型の識別を可能にするために特別な操作を行う必要はありません。

+0

@ user1202032これは最良の答えです。あなたの特定のケースでは、Matteo ItaliaのようなC#の使用反射が主な原因です。 – ForceMagic

3

ランタイムの型情報は、階層内の親クラスに少なくとも1つの仮想関数があるタイプで実際に機能します。 「vtable」ポインタは、仮想関数テーブルを指すとともに、そのタイプを識別する。 (原則として、少なくとも、仮想関数がどのように実装されるべきかを規格がどれほど厳密に規定しているかは覚えていない)仮想関数が全くない場合、その情報は効率のために除外される。

C#の型情報には常に仮想関数があります。

2

C++とC#の違いは深く、広大で、これは百科事典の脚注に違いがあります。

つまり、C#ではすべてのクラスが仮想関数を持つObjectから継承しなければならないため、オブジェクトに仮想関数がない場合があります。しかし、C++はそうしています。一般的に。したがって、C++では、実行時型の識別情報を入れる場所はありません。

+2

オブジェクトから継承するIMOはこれとあまり関係がありません。タイプの情報が常に利用可能であると判断されたのは、仮想関数がないかどうかです。 –

+0

@MattiVirkkunen:そのタイプ情報を入れる唯一の場所はvtableです。 – Puppy

+0

@DeadMG、仮想メソッドを持たない型であってもvtableを持つことを止めるのは何ですか? – svick