4

C++ と C# のこの違いの原因を理解するのに苦労しています。

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

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# との比較。ここで、"Base" と "Derived" は、2 番目の 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# はどのようにしてオブジェクトの型を正しく識別することができますか?

4

3 に答える 3

7

あなたが言うように: C++ は、クラスにvirtual関数がある場合にのみランタイム ポリモーフィズムと型識別を有効にします。これは、(一般的な実装では)vptrクラスに a が追加されることを意味します (これは、C++ の哲学と一致しています。必要のないもの」)。

(オブジェクトの型情報も?)

それでも、RTTI レコードへのポインターをクラスの vtable の最初のスロットに格納するのは一般的です。これが、クラスがポリモーフィックな場合にのみ RTTI が機能することを標準が要求する理由の 1 つだと思います (ただし、 、いつものように、これはすべてコンパイラに依存します)。

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

代わりに、C# では、すべてのクラスが既定でポリモーフィックであり、リフレクション メタデータが関連付けられているため、ポリモーフィズム/型の識別を有効にするために特別なことを行う必要はありません。

于 2012-03-15T20:43:32.183 に答える
3

C++ では、実行時の型情報は、階層内の親クラスに少なくとも 1 つの仮想関数がある型でのみ実際に機能します。「vtable」ポインターは、仮想関数テーブルを指し、型を識別します。(原則として、少なくとも、仮想関数の実装方法を標準がどの程度厳密に指定しているかは思い出せません) 仮想関数がまったくない場合、その情報は効率のために省略されます。

C# では、仮想関数であろうとなかろうと、型情報は常に存在します。

于 2012-03-15T20:44:40.347 に答える
2

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

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

于 2012-03-15T20:45:17.830 に答える