가상 상속을 받은 클래스의 size에 대해 공부하다가 의문이 든 부분..
class A{
char k[ 3 ];
public:
virtual void a(){};
};
class B : public A{
char j[ 3 ];
public:
virtual void b(){};
};
... 생략
int main(){
...
std::cout << sizeof(A) << std::endl;
std::cout << sizeof(B) << std::endl;
...
output >
16
16
B는 A를 상속받았는데 사이즈가 같다..! 🤷♀️ 왜!?
해답은 이 글에서 찾을 수 있었다.
[Stack Overflow] will the padding of base class be copied into the derived class?
#include <iostream>
using namespace std;
class A {
public:
int valA;
char a;
};
class B : public A {
public:
char b;
};
class C : public B {
public:
char c;
};
int main(){
std::cout << sizeof(A) << " " << sizeof(B) << " " << sizeof(C)
<< std::endl;
C c;
printf("c 주소 : %p\nc.a의 주소 : %p\nc.b의 주소 : %p\nc.c의 주소 : %p\n",&c,&c.a,&c.b,&c.c);
}
output >
8 12 12
c 주소 : 0x7ffee2be9840
c.a의 주소 : 0x7ffee2be9844
c.b의 주소 : 0x7ffee2be9848
c.c의 주소 : 0x7ffee2be9849
A클래스의 사이즈는 8, B클래스의 사이즈는 12, C클래스의 사이즈는 12이다.
C는 B를 상속받는데 어떻게 사이즈가 같을 수 있지?
이유를 정리해보자면 이렇다.
<정답은 아니다!!!!!!!!!!!!!!>
B는 A의 padding을 재사용하지 못했고, C는 B의 padding을 재사용했다.
POD class의 padding은 재사용할 수 없다.
A는 POD class이고 B는 POD class가 아니다.
👉 about POD
B is not a POD. so the padding of B can be reused for C::b.
The padding of A can't be reused for sub objects of B. because A is a POD class(= standard layout class, trivially copyable).
A:8 bytes = char:1 byte + int:4 bytes + pad: 3bytes
B:12 bytes = A:8bytes char:1 byte + pad: 3bytes
C:12 bytes = B:12 bytes - B's pad: 3bytes(reused) + char:1 byte
처음 코드를 다시 보면
class A{
char k[ 3 ];
public:
virtual void a(){};
};
class B : public A{
char j[ 3 ];
public:
virtual void b(){};
};
A는 virtual 키워드를 사용하고 멤버 함수도 존재하므로 POD class라고 할 수 없다. (= trivially copyable)
A:16 bytes = char:3 bytes + vptr:8 bytes + pad:5 bytes
B:16 bytes = A:16bytes - A's pad:5 bytes + char:3 bytes + pad:2 bytes
👏
최적화 과정에서 예상치 못하게 패딩을 복사하게된 걸 수도 있다.
memcpy는 객체가 potentially-overlapping이거나 trivially copyable가 아닌 경우 undefined한 결과를 얻게될 수 있다 되어있다.
-> potentially-overlapping경우에 base class subobject일 때가 포함돼있다.
-> potentially-overlapping 객체라 예상치 못한 결과가 나온 것일 수도 있다.
등등 다양한 의견들이 존재했다. 공식 문서에 적혀있는 내용은 아닌 것 같다.