[CPP] 상속2

9장. 가상 함수와 추상클래스

동기
- void print(Employee& e) {
e.printCheck();
}

SalariedEmployee se;
HourlyEmployee he;

print( se ); // a)
print( he ); // b)
a)의 경우 SalariedEmployee::printCheck()을
b)의 경우 SalariedEmployee::printCheck()을 호출해야 하지만,

a)와 b) 모두 Employee::printCheck()을 호출한다.
(사전 바인딩)

- 사전 바인딩으로 구현할 수 밖에 없었던 이유는
printCheck의 호출 객체로 실제 무엇이 e로 들어올지 모르기 때문에
선언된 클래스에 있는 printCheck을 호출하는 것이 최상의 방법이었다.

그럼에도 불구하고, 위의 예에서 알 수 있듯이, 이 방법만으로 충분하지 않다.

 

가상 함수
- virtual 키워드를 붙인 멤버 함수

다형성
- 기반 클래스에 정의한 가상 함수를 파생 클래스에서 오버라이딩(Overriding)하면
- 기반 클래스의 가상 함수를 호출하는 코드에서
1) 기반 클래스의 가상 함수가 호출될 수도 있고
2) 파생 클래스에서 오버라이딩한(재정의한) 함수가 호출될 수도 있다.

- class A {
virtual void f();
};

class B : public A {
void f();
}
(*)
A obj_a;

obj_a.f(); // 1) 번의 경우

(**)
A* p_a = new B();
p_a -> f(); // 2번의 경우

(***)
B obj_b;

g (obj_b);

int g (A& obj_a) {

obj_a . f(); // 2번의 경우

}
(*), (**), (***) 모두 A 클래스의 멤버 함수 f를 호출하지만
(*)에서는 A클래스의 f를 , (**)과 (***)에서는 B 클래스의 f를 호출함.

다형성! <= 호출객체에 따라 다른 클래스의 f를 선택해서 호출함.

 

다형성이 왜 유용한가?

- Sale 클래스에서 savings와 같은 메소드를 정의할 수 있다!
- virtual double bill() const { ... }
double Sale::savings(const Sale& other) const {
return bill() - other.bill();
}

만일 bill 멤버 함수가 virtual이 아니면 savings 멤버 함수는 쓸모 없다.
왜냐하면 ==> 슬라이드 5

다형성과 가상함수를 사용해서 정의하는 프로그램 예제
- Sale 클래스와 파생 클래스로 만든 프로그램 (본문 예제)
- Figure 클래스와 파생 클래스로 만든 프로그램 (프로그래밍 프로젝트 2번)
- Player 클래스와 파생 클래스로 만든 프로그램 (프로그래밍 프로젝트 5번)
- Creature 클래스와 파생 클래스로 만든 프로그램 (프로그래밍 프로젝트 4번)
============================================================================================
1) virtual로 선언한 함수 2) virtual 함수를 이용하여 다형성의 장점을 활용한 함수
============================================================================================
Sale 클래스 프로그램 bill() savings(Sale&, Sale&), operator<(Sale& Sale&)
Figure 클래스 프로그램 draw() center(Figure&)
Player 클래스 프로그램 getGuess() play(Player&, Player&)
Creature 클래스 프로그램 getDamage() battleArena(Creature&, Creature&)
============================================================================================

Q. Figure, Rectangle, Circle, Triangle 예제

class Figure {
protected:
int x, y;

public:
virtual void draw();
void center();
}

void Figure::draw() {
cout << "Figure: " << x << y;
}

void Figure::center() {
x = ... center ...;
y = ... center ...;
draw();
}
class Triangle : public Figure {
private int delta_x1, delta_x2, delta_x2, delta_x3;
public:
void draw();
}

void Triangle::draw() {
cout << "Triangle";
}

int main() {
Triangle t;

t.center(); // 삼각형을 화면 중앙으로 옮겨 그리기
}

t.center()를 호출
-> Figure::center() 호출
-> this->draw() 호출
(이때 this는 t의 주소)
-> Triangle::draw() 호출
(draw는 가상함수이므로 t의 실제 타입 Triangle의 draw를 선택해서 호출)

 

---
슬라이스 문제

1) Pet, Dog 클래스

Pet value_pet;
Dog value_dog;

...

value_pet = value_dog; // Dog 클래스의 breed는 복사되지 않는다.
// value_pet과 value_dog는 서로 다른 객체

value_pet.print(); // 가상 함수 print()는 Pet 클래스의 print()를 호출.

Pet* ppet;
Dog* pdog;

ppet = new Dog;
ppet->print(); // (*ppet).print() 와 동일.
// Dog 클래스의 print()를 호출.
// 왜? 비록 *ppet의 선언된 클래스는 Pet이지만
// 실제 객체의 클래스는 Dog!
pdog = dynamic_cast<Pet*>(ppet);

2) Sale, DiscountSale 클래스
double Sale::savings(const Sale other) { // other의 타입이 Sale임. Sale&가 아님!
return this->bill() - other.bill();
}
Sale s;
DiscountSale d;

s.savings( d ); // other = d; 와 같은 코드를 Sale 클래스의 복사 생성자에 의해 실행함
// 슬라이스 문제 발생
// 왜냐하면 s는 price 멤버변수만을 가지고 있고
// d는 price와 discount 멤버 변수를 가지고 있기 때문에
// price는 복사되지만 discount는 복사되지 않는다.
// 이때 , other.bill()은 항상 Sale 클래스의 bill

 
가상 함수를 사용하기 위해 virtual 키워드를 붙이는 것 뿐만 아니라
슬라이스 문제가 생기지 않도록 주의해야 한다. 그렇지 않으면,
제한적인 다형성만을 얻을 수 있다.
---

업캐스팅 (Up casting)
- 상속관계에 의한 형 호환성
- static_cast<...> ( ... )
다운캐스팅 (Down casting)

- dynamic_cast<... *>( ... )
[메모] x = y;에서 x와 y의 타입은 원칙적으로 반드시 같아야 한다.
value_pet = value_dog; 와 같이 이 원칙을 지키지 않는
프로그래밍을 할 수 있는 이유는 컴파일러가 적절한 코드를
추가해서 이 원칙을 지킬 수 있었기 때문이다.

value_pet = static_cast<Pet>(value_dog); 양쪽의 타입이 같다!

ppet = pdog; // ppet의 타입은 Pet*, pdog의 타입은 Dog*
// Dog*를 Pet*로 업캐스팅 가능
// 그 결과 양쪽의 타입이 같으므로 할당할 수 있음!

int* p = ppet;
// 양쪽 타입이 다르고,
// ppet의 Pet*을 int*로 변환할 수 있는 상속 관계가 있는 것도 아니다.
// 따라서 =를 사용할 때 양쪽의 타입을 같도록 만드는 원칙을 지키는
// 변환을 할 수 없으므로 컴파일 에러!
---
C++ 가상함수를 구현하는 방법

- 가상 함수 테이블
- 전자 칠판의 참고자료 mi.pdf

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *