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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// ##########################################
//
// 45 가상함수가 동작하는 원리
//
// ##########################################
//
//
// 다음과 같이 fct1, fct2, fct3는 모두 코드영역의
// 메모리 공간으로 올라가는데
// 클래스에 멤버함수중에서 하나라도 virtual로 선언되면
// 그 클래스의 멤버함수 정보를 지니는 버추얼테이블이 
// 형성된다.
// 모슨 A 클래스의 객체는 함수를 호출할 때 마다
// 버추얼테이블을 참조하게 된다.
// 이 버추얼테이블은 A 클래스의 fct1 함수가 어디에 있는지의
// 정보를 가지고 있고
// A 클래스의 fct2 함수가 어디에 있는지의 정보를 
// 가지고 있다.
// 즉 모든 멤버함수의 정보를 가지고 있다. 
// A 클래스의 aaa 객체의 fct1 함수를 호출하면
// 무조건 버추얼 테이블의 키값을 참조하게된다.
// fct1 함수의 key값을 찾고 value에 있는 위치찾아가 
// fct1 함수를 호출하게 된다.
// 즉, 가상함수를 선언함으로 인해서 버추얼테이블에 의한
// 메모리 소모와 버추얼 테이블을 참조함으로 인한 
// 함수 호출단계가 추가되어 함수 호출이 늦어지는 
// 단점이 있다.
// 
// B 클래스의 경우 A 클래스를 상속하기 때문에
// A 클래스의 멤버 함수도 멤버로 가지게 된다.
// 따라서 A클래스의 fct1, fct2, B 클래스의 fct1, fct3함수
// 의 정보를 버추얼테이블에서 가지고 있어야한다.
// 그러나 B클래스의 fct1에 의해서 오버라이딩된
// A 클래스의 fct1함수는 B 클래스의 버추얼테이블에
// 정보를 가지고 있지 않는다.
// 그래서 A 클래스의 포인터로 fct1 함수를 호출하던
// B 클래스의 포인터로 fct1 함수를 호출하던
// B 클래스의 fct1 함수만이 호출되는 것이다.
//
#include <iostream>
using std::endl;
using std::cout;

class A
{
	int a;
	int b;
public:
	virtual void fct1(){
		cout<<"fct1(...)"<<endl;
	}
	virtual void fct2(){
		cout<<"fct2(...)"<<endl;
	}	
};

class B : public A
{
	int c;
	int d;
public:
	virtual void fct1(){
		cout<<"overriding fct1(...)"<<endl;
	}
	void fct3(){
		cout<<"fct3(...)"<<endl;
	}
};

int main(void)
{
	A* aaa=new A();
	aaa->fct1();

	B* bbb=new B();
	bbb->fct1();
	
	return 0;
}

//
// 이러한 가상함수의 단점에도 불구하고
// 가상함수의 장점이 훨씬 크기 때문에
// 가상함수를 많이 사용한다.
//





Posted by 뮹실이

최근에 달린 댓글

05-19 04:14
Yesterday
Today
Total