virtual을 이용한 오버라이딩과 학부 시스템 프로그래밍 수업때 배운 바이트 패딩 복습
#include <iostream>
using namespace std;
class BASE
{
public:
BASE() { cout << "BASE()의 생성자" << endl; }
virtual ~BASE() { cout << "BASE()의 소멸자" << endl; };
public:
virtual void func1() { cout << "BASE()의 func1()" << endl; }
virtual void func2() { cout << "BASE()의 func2()" << endl; }
void func3() { cout << "BASE()의 func3()" << endl; }
public:
int iValue;
char CValue;
};
class CHILD1 : public BASE
{
public:
CHILD1() { cout << "CHILD1() 의 생성자" << std::endl; }
virtual ~CHILD1() { cout << "CHILD1() 의 소멸자" << std::endl; }
public:
virtual void func1() { cout << "CHILD1()의 func1()" << endl; }
void func2() { cout << "CHILD1()의 func2()" << endl; }
void func3() { cout << "CHILD1()의 func3()" << endl; }
public:
float fValue;
};
class CHILD2 : public CHILD1
{
public:
CHILD2() { cout << "CHILD2() 의 생성자" << std::endl; }
virtual ~CHILD2() { cout << "CHILD2() 의 소멸자" << std::endl; }
public:
virtual void func1() { cout << "CHILD2()의 func1()" << endl; }
void func2() { cout << "CHILD2()의 func2()" << endl; }
void func3() { cout << "CHILD2()의 func3()" << endl; }
};
class CHILD3 : public CHILD2
{
public:
CHILD3() { cout << "CHILD3() 의 생성자" << std::endl; }
virtual ~CHILD3() { cout << "CHILD3() 의 소멸자" << std::endl; }
};
int main()
{
// 문제 1) 출력되는걸 예상해보시오
BASE* base = new CHILD2;
base->func1();
base->func2();
base->func3();
delete base;
// 문제 2 ) 64비트 주소체계 기준 출력되는걸 예상해보시오
cout << sizeof(BASE) << endl;
cout << sizeof(CHILD1) << endl;
cout << sizeof(CHILD2) << endl;
return 0;
}
문제 1 답:
BASE()의 생성자
CHILD1() 의 생성자
CHILD2() 의 생성자
CHILD2()의 func1()
CHILD2()의 func2()
BASE()의 func3()
CHILD2() 의 소멸자
CHILD1() 의 소멸자
BASE()의 소멸자
-> 부모에 virtual을 붙이면 자식에 virtual을 안붙여도 재정의되긴 함. 다만 명시적으로 붙여주는게 좋을뿐
문제 2 답:
16
24
24
-> 가상 함수가 있는 클래스는 메모리 가장 먼저 가상함수 테이블이 추가된다. 64bit 주소체계니까 8바이트가 먼저 잡힌다.
그 후에 Base 클래스의 경우:
int iValue | char cValue | padding |
4byte | 1byte | 3byte |
따라서 Base 클래스의 vtable(8byte) + 8byte = 16byte
CHILD1,2,3 클래스의 경우
int iValue | char cValue | padding | float fValue | padding |
4byte | 1byte | 3byte | 4byte | 4byte |
따라서 vtable(8byte) + 16byte = 24byte
그런데 비슷한 유형인데 출력이 예상과 다른 경우가 있었다
#include <iostream>
using namespace std;
class A
{
char m_strName;
int m_iValue;
double m_dValue;
virtual void print() {};
};
class B
{
int* m_iSize;
virtual void print() {};
};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
}
32비트 주소 체계의 경우 출력은
24
8
64비트 주소 체계의 경우 출력은
24
16
32비트의 경우 A 클래스의 사이즈가 20일거라 생각했는데 24라고 나왔다. 그 이유는 클래스의 바이트 패딩은 직전 멤버와 비교해서 Padding 여부를 해주기 때문이다. 이게 무슨 이야기인지 자세히 설명해보자
virtual 함수가 있으니 4바이트의 vftable +
char 1byte (3byte 남음 -> 다음에 올 멤버가 int인데 남은 3byte에 넣지 못함 -> padding으로 3byte 채우기)
int 4bye (0byte 남음 -> 다음에 올 멤버가 double인데 남은 크기에 넣지 못함 -> padding으로 4byte 채우기)
double 8byte
= 4 + (1 + 3) + (4 + 4)+ 8 = 24byte
Reference
https://younggwan.tistory.com/57
'공부 > C++ Quiz' 카테고리의 다른 글
geeksforgeeks Output of C++ Program | Set 2 (0) | 2021.07.07 |
---|---|
geeksforgeeks Output of C++ Program | Set 1 (0) | 2021.07.07 |