C++에서 파생 대상 의 메모리 레이아웃 에 대해 간단히 말 합 니 다.

주로 세 가지 측면 에서 볼 때
단일 상속
2 다 중 상속
3 가상 상속
단일 상속
(1)파생 류 는 기본 적 인 메모리 구 조 를 완전히 가지 고 완전 성 을 확보한다.
파생 류 는 완전한 기본 클래스 인 Object 에 파생 류 자체 의 Object 로 볼 수 있다.기본 클래스 에 가상 구성원 함수 가 없다 면 파생 류 와 같은 기능 을 가 진 비 파생 류 는 어떠한 성능 상의 차이 도 가 져 오지 않 을 것 이다.또 기 류 의 완전 성 을 확보 해 야 한다.실제 메모리 레이아웃 은 컴 파일 러 가 스스로 결정 합 니 다.VS 에 서 는 가상 포인터 를 맨 앞 에 놓 고 그 다음 에 기본 클래스 의 Object 이 고 마지막 으로 파생 클래스 자신의 object 입 니 다.밤 을 들다

class A
{
  int b;
  char c;
};
class A1 :public A
{
    char a;
};
int main()
{
  cout << sizeof(A) << " " << sizeof(A1) << endl;
  return 0;
}
출력 이 뭐 예요?
답:
8 12
A 류 는 int 하나,char 하나,5B 메모리 정렬,8B.A1 이면 int 하나,char 두 개,메모리 정렬 도 8B 입 니 다.아닌가?
나 는 기본 대상 의 완전 성 을 확보 해 야 한다 고 말 했다.그러면 A1 류 앞의 몇 개의 바이트 가 반드시 A 류 와 똑 같 아야 한다.A 클래스 가 메모리 로 보완 되 는 3 개의 바이트 도 A1 에 들 어가 야 한 다 는 것 이다.즉,A 류 는 다음 과 같다.int(4B)+char(1B)+padding(3B)=8B,A1 류:int(4B)+char(1B)+padding(3B)+char(1B)+padding(3B)+padding(3B)=12B.
(2)가상 지침 은 어떻게 처리 합 니까?
아니면 컴 파일 러 를 보고 정 하 는 것 입 니까?VS 는 영원히 vptr 를 대상 의 맨 앞 에 두 는 것 입 니 다.기본 클래스 에 가상 함수 가 포함 되 어 있다 면 처리 상황 은 위 와 같 습 니 다.그러나 기본 클래스 에 허 함수 가 없어 파생 류 가 있다 면 vptr 를 파생 류 앞 에 두 면 파생 류 의 기본 성분 이 맨 앞 에 있 지 않 을 것 이다.이것 은 어떤 문 제 를 가 져 올 까요?밤 을 들다:A 는 허 를 함유 하지 않 고 A1 은 함유 하고 있다 고 가정 하 자.

A *pA;
A1 obj_A1;
pA=&obj_A1;
A1 이 A 를 완전히 포함 하고 A 가 A1 의 맨 앞 에 있다 면 컴 파일 러 는&obj 만A1 은 직접 pA 에 부여 하면 됩 니 다.아니면?컴 파일 러 는&objA1+sizeof(vptr)가 pA 에 부여 되 었 습 니 다.
2 다 중 상속
결론:VS 의 메모리 레이아웃 은 성명 순서에 따라 메모 리 를 배열 합 니 다.밤 을 하나 더 들다.

class point2d
{
public:
  virtual ~point2d(){};
  float x;
  float y;
};
class point3d :public point2d
{
  ~point3d(){};
  float z;
};
class vertex
{
public:
  virtual ~vertex(){};
  vertex* next;
};
class vertex3d :public point3d, public vertex
{
  float bulabula;
};


int _tmain(int argc, _TCHAR* argv[])
{
  cout << sizeof(point2d) << " " << sizeof(point3d) << " " << sizeof(vertex) << " " << sizeof(vertex3d) << endl;
  return 0;
}
출력:12,16,8,24.
메모리 레이아웃:
point2d: vptr(4)+x(4)+y(4)=12B
point3d: vptr+x+y+z=16B
vertex: vptr+next=8B
vertex3d: vptr+x+y+z+vptr+next+bulabula=28B
왜 여러 개의 빈 지침 이 필요 합 니까?아래 를 보 세 요.
3 가상 상속
(1)왜'가상 계승'이라는 메커니즘 이 있어 야 합 니까?
쉽게 말 하면 가상 계승 은'다이아몬드'의 계승 을 막 기 위 한 문제 다.즉,A1,A2 는 모두 A 에 계승 되 고 류 B 는 A1,A2 에 동시에 계승 된다.이렇게 되면 클래스 B 중 두 개의 클래스 A 의 구성원 이 있 는데 이런 프로그램 은 컴 파일 을 통과 할 수 없다.우 리 는 이런 형식 으로 바 꾸 었 다.

class A
{
public:
  int a;
  virtual ~A(); 
  virtual void fun(){cout<<"A"<<endl;}
};
class A1 :public virtual A
{
public:
  int a1;
  virtual void fun(){cout<<"A1"<<endl;}
};
class A2 :public virtual A
{
public:
  int a2;
  virtual void fun(){cout<<"A2"<<endl;}
}; 

class B :public A1,public A2 {
public:
  int b;
  virtual void fun(){cout<<"B"<<endl;}
  virtual void funB(){};
};
이렇게 하면 이런 일이 발생 하 는 것 을 방지 할 수 있다.
(2)가상 계승 과 일반 상속 의 차이 점:
일반 상속 으로 인해 파생 류 는 하나의 기 류 를 계승 할 때마다 기본 적 인 구성원 을 가지 게 된다.가상 상속 은 가상 을 통 해 물 려 받 은 부분 을 대상 의 마지막 에 놓는다.그래서 하나의 기본 클래스 의 구성원 만 가지 게 된다.가상 대상 의 오프셋 은 Derived 류 vtbl 의 this 가 가리 키 는 이전 slot 에 저 장 됩 니 다.이해 하기 어렵다.다음은 내 가 밤 하나 줄 게.
(3)가상 계승 메모리 레이아웃:
각 파생 류 는 변 하지 않 는 부분 을 앞 에 놓 고 공유 부분 을 뒤에 놓는다.
위의 네 가지 종류의 크기 는 어 떻 습 니까?

int _tmain(int argc, _TCHAR* argv[])
{
  cout << sizeof(A) << " " << sizeof(A1) << " " << sizeof(A2) << " " << sizeof(B) << endl;
  return 0;
}
출력:8 16 28
메모리 레이아웃:
    A: vptr+a=8B
    A1: vptr+a1+vptrA+a=16B
    A2: vptr+a2+vptrA+a=16B
    A3: vptr+a1+vptrA2+a2+b+vptrA+a=28B
이전 스케치:

그런데 도대체 왜 여러 개의 빈 지침 이 필요 합 니까?대상 의 메모리 레이아웃 과 가상 표 구 조 를 밝 힌 후에 답 이 나 오 려 고 하 는 것 이 아 닙 니까?
예,이렇게 하면 하위 포인터/인용 을 기본 포인터 로 변환 할 때 컴 파일 러 는 이미지 의 메모리 레이아웃 에 따라 직접 오프셋 을 하여 가리 키 는 첫 번 째 내용 을 가상 포인터 로 하여 다 중(정적 유형 에 따라 해당 동작 을 수행)을 실현 할 수 있 기 때 문 입 니 다.
이상 은 여러분 에 게 가 져 온 간단 한 이야기 입 니 다.C+에서 파생 된 대상 의 메모리 레이아웃 의 모든 내용 입 니 다.많은 응원 부 탁 드 리 겠 습 니 다~

좋은 웹페이지 즐겨찾기