티스토리 뷰
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 클래스 멤버가 하나씩만 존재하게 된다.
'프로그래밍 > 윤성우의 열혈 C++' 카테고리의 다른 글
Chapter 12 String 클래스의 디자인 (0) | 2022.03.15 |
---|---|
Chapter 11 연산자 오버로딩 2 (0) | 2022.03.14 |
08 상속과 다형성 (0) | 2022.03.10 |
Chapter 07 상속(Inheritance)의 이해 (0) | 2022.03.09 |
Chapter 06 friend와 static 그리고 const (0) | 2022.03.08 |
- Total
- Today
- Yesterday
- 코딩테스트
- 회계
- C/C++
- 통계
- 백준
- 데이터분석
- 윤성우
- 여인권
- 류근관
- 열혈프로그래밍
- c++
- 사회심리학
- 티스토리챌린지
- Python
- 인지부조화
- C
- 일본어
- 오블완
- 일문따
- 인프런
- K-MOOC
- 통계학
- 파이썬
- 뇌와행동의기초
- 심리학
- 보세사
- jlpt
- 강화학습
- stl
- 일본어문법무작정따라하기
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |