[c++] 다형성, 가상 함수

다형성(polymorphism)

  • 똑같은 메시지가 전달되더라도 객체들의 타입이 다르면 서로 다른 동작을 하는것
  • 객체 포인터를 통해 이루어진다.

객체 포인터의 형변환

Dog dog; // Dog 타입의 객체
Animal *pa; // Animal 객체 포인터
pa = &dog; // Animal 객체 포인터로 Dog 타입의 객체를 가리킨다
  • 부모 클래스 포인터는 자식 객체도 가리킬 수 있다.
  • = 상향 형변환(up-casting)
  • 그 반대는 하향 형변환(down-casting)

상향 형변환

  • 다만 자식 클래스 객체에 선언된 부분은 사용하지 못한다. (교집합인 부모 데이터만 사용 가능)

하향 형변환

Shape *ps = new Rectangle( );
Rectangle *pr = (Rectangle *)ps;
pr->setWidth(100);
((Rectangle *)ps)->setWidth(100);

*형 변환 오류를 방지하는 방법

  • dynamic_cast 형변환 연산자 사용
    DerivedClass *pd = dynamic_cast<DerivedClass *>(pb);
    

가상 함수

class Shape {
	...
}
class Rectangle : public Shape {
	...
}
int main()
{
	Shape *ps = new Rectangle(); // OK!
	ps->draw(); // 어떤 draw()가 호출되는가?
}
Shape Draw
  • 자식 클래스의 재정의된 함수가 호출되게 하려면, 부모 클래스의 함수를 가상함수로 정의하자

    ...
    virtual void draw() { 
        cout <<"Shape Draw" << endl;
    }
    ...
    

동적 바인딩(binding)

  • 함수 호출을 함수의 몸체와 연결하는 것

  • 정적 바인딩(static binding)

  • 동적 바인딩(dynamic binding), 지연 바인딩(late binding)

바인딩의 종류 특징 속도 대상
정적 바인딩 컴파일 시간에 호출 함수가 결정 빠르다 일반 함수
동적 바인딩 실행 시간에 호출 함수가 결정 늦다 가상 함수
  • 가상함수가 아닌 모든 함수는 정적 바인딩으로 호출

참조자와 가상 함수

  • 포인터를 사용한 다형성과 동일하다.
    int main()
    {
        Dog d;
        Animal &a1 =d;
        a1.speak();
        Cat c;
        Animal &a2 =c;
        a2.speak();
        return 0;
    }
    

가상 소멸자

  • 다형성을 사용할때는 소멸자를 virtual로 지정해야 한다.

순수 가상 함수(Pure Virtual Function)

  • 헤더만 존재하고 몸체는 없는 함수
    virtual void draw( ) = 0;
    

추상 클래스(abstract class)

- 순수 가상 함수를 하나라도 가지고 있는 클래스
- 추상적인 개념을 표현할 수 있다.
- 객체를 생성할 수 없다.
	- 포인터 변수는 생성할 수 있다.
		- 자식 클래스의 객체를 가리킬 수 있다.