2011-09-30 4 views
0
class classWithNoVirtualFunction 
{ 
    public: 
     int a; 
     void x() 
     { 
      char c; 
      c = 'a'; 
     } 
}; 

class classWithOneVirtualFunction 
{ 
public: 
    int   a; 
    virtual void x() {} 
}; 

class classWithTwoVirtualFunctions 
{ 
public: 
    int   a; 
    virtual void x() {} 
    virtual void y() {} 
}; 

int main() 
{ 
    cout << "\nclassWithNoVirtualFunction's size: " << sizeof (classWithNoVirtualFunction);  
    cout << "\nclassWithOneVirtualFunction's size: " << sizeof (classWithOneVirtualFunction); 
    cout << "\nclassWithTwoVirtualFunctions's size: " << sizeof (classWithTwoVirtualFunctions); 

    cout << "\nvoid*'s size : " << sizeof (void*); 
} 

위의 코드, C의 생각은 ++ 말한다 W.R.T :가상 함수 만 포함 된 클래스의 크기가 영향을받는 이유는 무엇입니까?

적어도 하나의 데이터 멤버 필요한이 예. 데이터 멤버가 없으면 C++ 컴파일러는 각 개체가 고유 한 주소를 가져야하므로 크기가 아닌 개체를 강제로 적용하게됩니다. 크기가 0 인 객체 배열에 대한 인덱싱을 생각하면 을 이해할 수 있습니다. "더미"멤버는 이 0 인 객체에 삽입됩니다.

내 질문 : 지금, 나는 을 이해 할 수없는 나는 우리가 제로 회원들과 가상 함수와 클래스가있는 경우이 발생하는 방법을 정확하게 & &. 몇 가지 프로그래밍 예제로 설명하십시오.

+0

내가 어떻게 프로그래밍 예제를 설명 할 수 있을지 모르겠다 * 당신이 이미 추가 한 것 이상 ('int'을 제거한 것). BTW, 프로그램의 예상 출력은 (1, x, x, x)입니다. 여기서 x는 아키텍처의 포인터 크기 (일반적으로 32/64 비트 아키텍처의 경우 4/8)입니다. –

+1

@ DavidRodríguez-dribeas 엄밀히 말하면, 첫 번째 출력은 1이 아니고 단지 0이 아니라는 요구 사항은 없습니다. Unisys 메인 프레임이라는 워드 어드레싱 머신에서, 나는 단어의 크기가 될 것으로 기대합니다. 값은 동일해야합니다. 엄밀히 말하면 나머지 값도 동일해야한다는 요구 사항이 없습니다. 나는'void *'가'vptr'에 필요한 것보다 큰 하드웨어에서 일했습니다. (하지만 C++ 시대 이전에는 그런 짐승이 아직 없다고 생각합니다.) –

답변

5

클래스에 하나 이상의 가상 함수가 포함되어있을 때마다 컴파일러에서 각 객체에 런타임 유형 정보를 추가해야합니다. 구현은 보통 컴파일러에 의해 정의되고 사용자로부터 숨겨진 구조를 참조하는 각 객체에 하나의 포인터를 추가합니다. type_info 객체에 대한 포인터와 vtable은 함수의 동적 디스패치에 사용됩니다.

비 정적 데이터 멤버가없고 하나 이상의 가상 함수가없는 클래스의 경우 각 객체의 크기는 객체 별 RTTI 정보 (하나의 포인터)의 크기이며, 0이면 컴파일러에서 추가 공간을 추가하지 않습니다. 견적이 말하는 것은 T의 모든 유형에 대해 sizeof(T) != 0이며 동적 기능이있는 유형이 해당 요구 사항에 적합합니다. 크기가 0 인 유형에서만 컴파일러는 객체 1을 크게 만들 수밖에 없습니다.

+0

그리고'RunTime Type Information'은 무엇입니까?나는 이것을 이해하지 못했다. 각 객체의 크기는 객체 당 RTTI 정보 (하나의 포인터)의 크기이고, 그것이 0이 아니기 때문에 컴파일러는 여분의 공간을 추가하지 않을 것이다. '나는 당신의 대답을 잘 이해하지 못했습니다. –

+0

RTTI is RunTime Type 정보에는 유형 정보와 함수 디스패치를위한 가상 테이블이 모두 포함됩니다. 가상 함수가없는 객체의 경우, 포인터 나 참조를 통해 액세스되는 객체의'typeid'는 포인터 또는 참조의 정적 유형입니다 :'nonvirtual * p = f(); typeid (* p);'는 컴파일 타임에'typeid (nonvirtual)'으로 해석되지만,'virt' 타입에 가상 함수가 있으면'virt * p = f(); typeid (* p);'는 대부분의 파생 된 객체의 유형 정보를 제공합니다.이 객체는 virt 또는 그 객체에서 파생 된 객체 일 수 있습니다. –

+0

RTTI의 두 번째 측면은 디스패치 메커니즘의 일반적인 구현 인 가상 테이블입니다. 기본적으로 개체의 모든 가상 함수에 대한 함수 포인터를 포함하는 테이블입니다. 계층 구조의'base' 하위 객체는 하나의 테이블 ('vptr')에 대한 하나의 포인터를 포함 할 것이고, 계층 구조 내의 각각의'derived' 타입은'vptr'를 덮어 써서 다른 vtable을 가리킬 것입니다. * final-overrider * 각 레벨의 가상 함수들. 효율성을 위해,'type_info'와'vtable'은 구조체 안에 함께 묶여 있고, 각각의 객체는 하나의 포인터를 가지고 있습니다. –

0

C++ 표준은 클래스의 전체 레이아웃을 정의하지 않습니다. 이것은 컴파일러 벤더에 달려 있습니다. 그러나 C++ 표준은 일부 보증을합니다. 예를 들어, 완전한 객체의 크기는 항상 0보다 큽니다. 이 규칙에 대한 이유는 Thinking in C++에서 인용 한 텍스트에 암시됩니다. 간단한 클래스의 가상 함수는 이고 일반적으로은 객체의 동적 유형을 식별하는 추가 숨겨진 포인터 멤버로 구현되므로 객체의 동적 유형에 대한 올바른 함수를 호출 할 수 있습니다. 이 추가 숨겨진 멤버가 클래스 크기에 추가되기 때문에 컴파일러는 클래스에 0이 아닌 크기가되도록 패딩을 둘 필요가 없습니다.

하지만 대부분 구현에 대한 세부 정보이므로 걱정하지 않아도됩니다. C++ 표준이 보장하는 것에 의존한다면, 괜찮을 것입니다.

관련 문제