2012-03-15 4 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()를 제거하면 더 이상 작동하지 않습니다. 출력은 "Base"입니다. 예 :

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#과의 흥미로운 부분을 비교해보십시오.

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()); 
     } 
} 

내 질문은 따라서이다 : 여기서, "파생" "자료"및 2 C와 유사한 빈 클래스 ++ 예제는 기본적으로있는 것은 일부 올바른 ++은 C에 대한 이해, 그리고 어떻게 C#을 제대로 식별하기 위해 관리 않습니다 C++이 없을 때 객체의 타입?

+1

이 기사는 C#의 배경에서 이것이 어떻게 구현되는지 이해하는 데 도움이 될 것입니다. http://msdn.microsoft.com/ko-kr/magazine/cc163791.aspx - 개체 레이아웃 섹션을 참조하십시오. –

답변

6

C++은 클래스에 virtual 함수가있을 때만 런타임 다형성과 유형 식별을 가능하게합니다. 이는 일반적인 구현에서 vptr이 클래스에 추가됨을 의미합니다 (이것은 C++의 철학과 일관됩니다) 너는 너가 필요로하지 않는 것을 위해 돈을 내지 않는다. "). (?뿐만 아니라 개체의 형식 정보)

그러나, 그것은 클래스의 VTABLE의 첫 번째 슬롯에 RTTI 레코드에 대한 포인터를 저장하는 데 일반적입니다 - 내가 좋겠 이것은 클래스가 다형성 인 경우에만 표준이 RTTI를 필요로하는 이유 중 하나라고 말합니다 (평소와 같이이 모든 것이 컴파일러에 종속적 임에도 불구하고).

그런데 RTTI는 가상 디스패치가 올바르게 작동하는 데 필요하지 않습니다. 모든 컴파일러가 수행해야하는 가상 함수를 호출하면 vtable의 올바른 슬롯에서 가져온 포인터로 call ptr을 수행해야합니다. RTTI 레코드는 dynamic_cast의 클래스 계층 구조를 검사 할 때 및 typeid을 통해 오브젝트 유형에 대해 명시 적으로 묻는 경우에만 사용됩니다.

C#에서는 모든 클래스가 기본적으로 다형성을 가지며 리플렉션 메타 데이터가 연결되어 있으므로 다형성/형식 식별을 위해 특별한 작업을 수행 할 필요가 없습니다.

+0

@ user1202032 Matteo Italia와 같은 C# 사용 반사가 주로 발생했기 때문에 이것이 가장 좋은 답변입니다. – ForceMagic

3

C++에서 런타임 유형 정보는 실제로 계층 구조의 상위 클래스에 하나 이상의 가상 함수가있는 유형에서만 작동합니다. "vtable"포인터는 유형을 식별 할뿐만 아니라 가상 함수 테이블을 가리 킵니다. (원칙적으로 표준이 얼마나 가상 함수가 구현되어야 하는지를 얼마나 엄격하게 지정했는지는 기억할 수 없다.) 가상 함수가 전혀 없다면 그 정보는 효율적이지 않다.

C# 유형 정보에는 항상 가상 함수가 있거나 없습니다.

2

C++과 C#의 차이점은 깊고 광범위하며 차이점에 대한 백과 사전의 각주에 불과합니다.

즉, C#에서는 모든 클래스가 가상 함수가있는 Object를 상속해야하므로 C#에서는 결코 가상 함수가없는 경우가 있습니다. 그러나 C++은 그렇습니다. 천하게. 그래서 C++에서는 런타임 타입 식별 정보를 넣을 곳이 없습니다.

+2

개체에서 상속받는 IMO는 이와 관련이별로 없으며 가상 함수가 없어도 유형 정보를 항상 사용할 수 있다고 결정했습니다. –

+0

@MattiVirkkunen : 해당 유형 정보를 넣을 수있는 유일한 장소는 vtable입니다. – Puppy

+0

@DeadMG, 버추얼 메소드가없는 유형의 경우에도 vtable을 사용하지 못하게하려면 어떻게해야합니까? – svick