티스토리 뷰

반응형

09-1 멤버함수와 가상함수의 동작원리

 

 

객체 안에 정말로 멤버함수가 존재하는가?

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

class Data
{
private:
	int data;
public:
	Data(int num):data(num)
	{}
	void ShowData() { cout << "Data: " << data << endl; }
	void Add(int num) { data += num; }
};

int main(void)
{
	Data obj(15);
	obj.Add(17);
	obj.ShowData();
	return 0;
}

 

C++의 객체

 

#include <iostream>
#include <cstring>
using namespace std;

typedef struct Data
{
	int data;
	void (*ShowData)(Data*);
	void (*Add)(Data*, int);
}Data;

void ShowData(Data* THIS) { cout << "Data: " << "THIS->data" << endl; }
void Add(Data* THIS, int num) { THIS->data += num; }

int main(void)
{
	Data obj1 = { 15,ShowData,Add };
	Data obj2 = { 7,ShowData,Add };

	obj1.Add(&obj1, 17);
	obj2.Add(&obj2, 9);
	obj1.ShowData(&obj1);
	obj2.ShowData(&obj2);
	return 0;
}

C 스타일의 구조체이다.

obj1가 obj2는 Add함수를 공유한다.

 

'C++의 클래스에서 멤버변수는 객채 내에 존재하지만, 멤버함수는 메모리에 한 공간에 별도로 위치하고, 이 함수가 정의된 모든 클래스의 모든 객체가 이를 공유한다.'

 

 

가상함수의 동작원리와 가상함수 테이블

 

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

class AAA
{
private:
	int num1;
public:
	virtual void Func1() { cout << "Func1" << endl; }
	virtual void Func2() { cout << "Func2" << endl; }

};

class BBB :public AAA
{
private:
	int num2;
public:
	virtual void Func1() { cout << "BBB::Func1" << endl; }
	void Func3() { cout << "Func3" << endl; }
};

int main(void)
{
	AAA* aptr = new AAA();
	aptr->Func1();

	BBB* bptr = new BBB();
	bptr -> Func1();
	return 0;
}

결과

Func1

BBB::Func1

 

한 개 이상의 가상함수가 포함된 클래스에 컴파일러는 가상함수 테이블이라는 것을 만든다.

 

key value
void AAA::Func1( ) 0x1024 번지
void AAA::Func2( ) 0x2048 번지

AAA 클래스의 가상함수 테이블

 

key value
void BBB:Func1( ) 0x3072번지
void AAA:Func2( ) 0x2048번지
void BBB:Func3( ) 0x4096번지

BBB 클래스의 가상함수 테이블

 

 이런 가상함수 테이블을 참조해 함수를 호출하는데, AAA::Func1()이 BBB의 가상테이블에서 없다. 이는 AAA::Func()에 선언된 virtual 선언이 이를 삭제하기 때문이다.

 

가상함수 테이블이 참조되는 방식

 

 

각각의 객체는 함수만 공유하는 것이 아니라 V테이블도 공유한다!

 

 

09-2 다중상속(Multiple Inheritance)

 

다중상속에 대한 견해

'다중상속은 득보다 실이 더 많은 문법이다. 그러니 절대 사용하지 말아야하며 기본 문법에서 제외해야한다.'

 

다중상속의 기본방법

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

class BaseOne
{
public:
	void SimpleFuncOne() { cout << "BaseOne" << endl; }

};

class BaseTwo
{
public:
	void SimpleFuncTwo() { cout << "Base Two" << endl; }

};

class MultiDerived :public BaseOne, protected BaseTwo
{
public:
	void ComplexFunc()
	{
		SimpleFuncOne();
		SimpleFuncTwo();
	}
};

int main(void)
{
	MultiDerived mdr;
	mdr.ComplexFunc();
	return 0;
}

 

다중상속은 그냥 두 개를 나란히 상속시키면 된다.

 

 

다중상속의 모호성(Ambiguous)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

class BaseOne
{
public:
	void SimpleFuncOne() { cout << "BaseOne" << endl; }

};

class BaseTwo
{
public:
	void SimpleFuncTwo() { cout << "Base Two" << endl; }

};

class MultiDerived :public BaseOne, protected BaseTwo
{
public:
	void ComplexFunc()
	{
		BaseOne::SimpleFuncOne();
		BaseTwo::SimpleFuncTwo();
	}
};

int main(void)
{
	MultiDerived mdr;
	mdr.ComplexFunc();
	return 0;
}

 

ComplexFunc에서 도대체 어떤 함수에 접근하라는 건지 알기가 어렵다!

BaseOne:: 으로 이름공간을 명시해서 알려준다.

 

 

가상 상속(Virtual Inheritance)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

class Base
{
public:
	Base() { cout << "Base Constructor" << endl; }
	void SimpleFunc() { cout << "BaseOne" << endl; }
};

class MiddleDerivedOne :virtual public Base
{
public:
	MiddleDerivedOne() :Base()
	{
		cout << "MiddleDerivedOne Constructor" << endl;
	}
	void MiddleFuncOne()
	{
		SimpleFunc();
		cout << "MiddleDrivedOne" << endl;
	}
};

class MiddleDerivedTwo : virtual public Base
{
public:
	MiddleDerivedTwo() :Base()
	{
		cout << "MiddledrivedTwo Constructor" << endl;
	}
	void MiddleFuncTwo()
	{
		SimpleFunc();
		cout << "MiddleDerivedTwo" << endl;
	}
};

class LastDerived :public MiddleDerivedOne, public MiddleDerivedTwo
{
public:
	LastDerived() :MiddleDerivedOne(), MiddleDerivedTwo()
	{
		cout << "LastDerived Constructor" << endl;
	}
	void ComplexFunc()
	{
		MiddleDerivedOne();
		MiddleDerivedTwo();
		SimpleFunc();
	}
};

int main(void)
{
	cout << "객체생성 전...." << endl;
	LastDerived idr;
	cout << "객체생성 후....." << endl;
	idr.ComplexFunc();
	return 0;
}

 

virtual 상속을 하면 하나만 상속한다.

 

LastDerived 객체 내에는 MiddleDrivedOne과 MiddleDrivedTwo를 동시에 상속하면서 Base 클래스 멤버가 하나씩만 존재하게 된다.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함
반응형