공부/C++ Quiz

가상 함수를 갖고 있는 클래스의 바인딩과 사이즈 예상 문제

sudo 2022. 8. 26. 16:20

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++ 바이트패딩 Byte Padding (두번째!)

https://younggwan.tistory.com/41 class TestClass { char m_Temp_Char[2]; int m_Temp_Int;.." data-og-host="younggwan.tistory.com" data-og-source-url="https://younggwan.tistory.com/41" data-og-url="htt..

younggwan.tistory.com

 

'공부 > C++ Quiz' 카테고리의 다른 글

geeksforgeeks Output of C++ Program | Set 2  (0) 2021.07.07
geeksforgeeks Output of C++ Program | Set 1  (0) 2021.07.07