Automotive Software

다형성 (Polymorphism) 본문

프로그래밍 (Programming)/C++ (C Plus Plus) 기초

다형성 (Polymorphism)

AutoSW 2021. 1. 7. 05:29
  • 다형성의 기본 : 프로그램 실행 시에 필요로 하는 파생 클래스(들)의 객체를 베이스 클래스의 객체 포인터에 연결하는 기능
  • 단일 상속 (Single Inheritance)
    • 하나의 베이스 클래스로부터 상속받아 파생 클래스 생성
    • 확장성에서 제한을 가질 수 있으나, 명확한 클래스 간의 관계를 나타낼 수 있음
    • 주의 사항
      • 파생 클래스 멤버 메소드의 상향 흡수 (Percolating Upward)
        • 몇몇 파생 클래스에서만 필요한 메소드를 최소화가 중요한 공통 베이스 클래스에 구현
      • 베이스 클래스 포인터의 하향 형변환 (Casting Down)
        • 베이스 클래스를 가리키는 포인터가 파생 클래스 내에 구현된 메소드를 호출하기 위해 파생 클래스의 포인터 형으로 변환하는 것
        • 실행 시 형 식별(RTTI : Run Time Type Identification) 또는 dynamic_cast 연산자를 통해 지원
  • 다중 상속 (Multiple Inheritance)
    • 하나 이상의 베이스 클래스로부터 상속받아 파생 클래스 생성
      • 파생  클래스 이름 뒤에 콜론 후 각 베이스 클래스를 쉼표로 구분
    • 확장성을 가지나 클래스 간의 관계에 모호성을 가짐
      • 같은 이름의 가상 함수나 가상 자료를 가질 경우
    • 오직 C++에서 지원(자바 지원 않함)하며 프로그램의 복잡도를 높이므로 사용 시 주의
class cMyBaseClass1
{
pubic:
	int baseMemFunc(){return baseMemVar;}
privat:
	int baseMemVar;
};

class cMyBaseClass2
{
pubic:
	int baseMemFunc(){return baseMemVar;}
privat:
	int baseMemVar;
};

// Single Inheritance
class cMyClass : public cMyBaseClass1
{
public:
	memFunc();
};

// Multiple Inheritance
class cMyClass : public cMyBaseClass1, cMyBaseClass2
{
public:
	memFunc();
};

 

  • 다중 상속 시 모호성
    • 상기 예제에서와 같이 다중 베이스 클래스로 부터클래스로부터 상속을 받을 때, 두 베이스 클래스가 동일한 멤버를 가지는 경우 파생 클래스에서는 어떠한 베이스 클래스로부터 해당 멤버를 상속받을지 명시해 줘야 함
    • 해결법
      1. 참조해야할 베이스 클래스를 명시
      2. 파생 클래스에서 해당 메소드를 재생
class cMyBaseClass1
{
pubic:
	virtual int baseMemFunc() const {return baseMemVar;}
privat:
	int baseMemVar;
};

class cMyBaseClass2
{
pubic:
	virtual int baseMemFunc() const {return baseMemVar;}
privat:
	int baseMemVar;
};

// 1. 직접 명시를 통한 해결
int main(void)
{
	...
	int lBaseMemVar = pMyClass->cMyBaseClass1::baseMemFunc();
	...
}

// 2. 함수 재생을 통한 해결
class cMyClass : public cMyBaseClass1, cMyBaseClass2
{
public:
	memFunc();
	virtual int baseMemFunc() const {return cMyBaseClass1::baseMemVar;}
};

 

  • 가상 상속
    • 단일 공통 베이스 클래스를 가지기 위해 중간 단계의 파생 클래스(들)를 가상화하고 최종 파생 클래스가 단일 베이스 클래스를 참조하도록 구현
    • 아래의 예제에서 cMyClass 객체에서 호출하는 baseMemFunc()는 cMyBaseClass의 baseMemVar을 반환
class cMyBaseClass
{
pubic:
	virtual int baseMemFunc() const {return baseMemVar;}
privat:
	int baseMemVar;
};

class cMyInterClass1 : virtual public cMyBaseClass
{
public:
	virtual baseMemFunc() const {return interMemVar1;}
privat:
	int interMemVar1;    
};

class cMyInterClass2 : virtual public cMyBaseClass
{
public:
	virtual baseMemFunc() const {return interMemVar2;}
privat:
	int interMemVar2;    
};

class cMyClass : public cMyInterClass1, public cMyInterClass2
{
public:
	memFunc();
	virtual int baseMemFunc() const {return cMyInterClass1::baseMemFunc();}
};

 

  • 추상 자료형 (Abstract data type)
    • 다중 상속의 사용을 회피할 수 있는 좋은 수단
    • 자신에게서 파생된 클래스에게 인터페이스만 제공하여 확장성 보장
    • 항상 베이스 클래스로써 존재하며 구체적인 구현이 누락되어 있어 객체화는 되지 않음
    • 하나이상의 순수 가상 함수(Pure Virtual Function)를 가진 클래스
      • 구현도 가능하나 주로 파생 객체와의 인터페이스에 대한 정의로만 사용
      • 실제 구현은 파생 클래스에서 재생하여 정의
      • 함수를 0으로 초기화 함으로써 정의
class cMyBaseClass
{
pubic:
	virtual int baseMemFunc() = 0;
privat:
};