일지

Effective C++...33

niamdank 2022. 8. 4. 21:25

가상 함수 대신 쓸 것들도 생각해 두는 주세를 시시때때로 길러 두자

가상 함수를 대체할 수 있는 방법들

어떤 공통적인 연산을 수행하는 함수를 구현할 때 가상 함수 대신 다음과 같은 구현도 가능하다.

  • 비가상 함수 인터페이스 관용구 비가상 함수로 가상 함수를 감싸서 가상 함수를 감추는 방법
  • 함수 포인터 전략 패턴 함수 포인터를 이용해 외부 함수를 사용하는 방법
  • tr1::function 전략 패턴 STL 라이브러리를 이용해 일반적인 형태의 함수를 사용하는 방법
  • 고전적인 전략 패턴 공통 연산을 수행하는 함수를 가진 클래스 계열을 생성해 사용하는 방법

 

비가상 함수 인터페이스 관용구 예제와 특징

비가상 함수를 호출할 수 있도록 하고 private 가상 함수를 만들어 상속된 클래스에 따라 구현을 달리할 수 있다.


class GameCharacter {

public:

   int healthValue() const

    {

        ...

        int retVal = doHealthValue();

        ...

    }

private:

    virtual int doHealthValue const { ... };

};


 

※ 자유롭게 계산 함수를 구현할 수 있으나 호출 순서는 최상위 함수에서 결정 되어 있다.

 

함수 포인터 전략 패턴 예제와 특징

생성자에서 계산에 사용할 함수의 포인터를 받아 실제 계산 시에 사용한다.


// 실제 계산을 위한 함수

int defaultHealthCalc(const GameCharacter& gc);

 

class GameCharacter {

public:

    // 계산에 사용할 함수 포인터 타입 정의

   typedef int (*HealthCalcFunc)(const GameCharacter&);

 

   int healthValue() const { return healthFunc(*this); }

private:

    HealthCalcFunc healthFunc;

};


 

※ 같은 타입의 인스턴스도 계산 함수를 다르게 가질 수 있으며, 게임 실행 도중 처리 함수를 바꿀 수도 있다.

 

tr1::function 전략 패턴 예제와 특징

함수 포인터 전략 패턴과 동일한 구현이지만 STL 라이브러리를 사용하여 조금 더 범용성을 높였다.


class GameCharacter {

public:

    // 기존과 같지만 타입이 tr1::function으로 바뀌었다.

   typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc;

 

   int healthValue() const { return healthFunc(*this); }

private:

    HealthCalcFunc healthFunc;

};


 

※ STL 라이브러리를 사용하여 단순히 HealthCalcFunc와 같은 함수뿐만 아니라 그러한 형식을 가진 모든 함수를 사용할 수 있다.

 

고전적인 전략 패턴 예제와 특징

가상 계산 함수를 가지는 클래스를 선언해 필요에 따라 상속해 새로운 클래스를 만들어 사용하고 해당 클래스를 전달해 사용하는 방식이다.


class GameCharacter;

class HealthCalcFunc {

public:

    ...

    virtual int calc(const GameCharacter& gc) const { ... }

    ...

};

HealthCalcFunc defaultHealthCalc;

 

class GameCharacter {

public:

    explicit GameCharacter(HealthCalcFunc *phcf = &defaultHealthCalc)

            : pHealthCalc(phcf) { }

    int healthValue() const { return pHealthCalc->calc(*this); }

private:

    HealthCalcFunc* pHealthCalc;

};


 

※ 쉽게 이해할 수 있고 계산 클래스의 파생 클래스로 함수를 조절할 수 있는 가능성을 열어뒀다.