본문 바로가기

프로그래밍/C++

C++11 재정의규칙과 override



class A{

public:

virtual void doWork() { printf(" I am A");}

};


class B : public A

{

public:

virtual void doWork(); { printf(" I am B");}

};


using namespace std;


unique_ptr<A> object = make_unique<B>();


object->doWork();


하면 어떻게 될까?


B클래스에서 doWork()를 재정의 하였기 때문에


당연히 "I am B" 가 출력이 된다.



이와 같이 멤버함수의 재정의를 하기 위해선 몇 가지 조건을 만족해야 한다.


* 기본 클래스 함수가 반드시 가상 함수이어야 한다.


* 기본 함수와 파생 함수의 이름이 반드시 동일해야 한다 (소멸자는 예외)


* 기본 함수와 파생 함수의 파라미터 형식들이 동일해야 한다.


* 기본 함수와 파생 함수의 const 성이 동일해야 한다.


* 기본 함수와 파생 함수의 반환 형식과 예외 명세가 반드시 호환되어야 한다.



여기까지는 C++98 에도 있던 것이다.


그리고 C++11 에는 다음과 같은 조건이 하나 더 추가된다.


멤버 함수들의 참조 한정사(reference qualifier)들이 동일해야 한다.



그렇다면 참조 한정사가 뭘까?


멤버 함수를 왼값 또는 오른쪽값에만 사용할 수 있게 제한할 수 있는 기능이다.


이렇게 설명하면 뭔말인지 잘 모를테니


예제를..



class Widget {

public:


void doWork() &;        // *this가 왼값일때만 적용

void doWork() &&;      // *this가 오른값일때만 적용  

};



Widget makeWidget(); // 인스턴스를 생성 및 반환하는 함수를 만들었다고 가정


Widget w; // w 라는 왼쪽값 생성




그리고 다음과 같이 호출해보자.



makeWidget().doWork(); // void doWork() & 호출


w.doWork(); // void doWork() && 호출


=> 왼쪽,오른쪽값에 따라 다른 멤버함수가 호출되는 것을 볼 수 있다.





다음은 override 에 대한 설명이다.


class A{

public:

virtual void mf1() const;

virtual void mf2(int x);

virtual void mf3() &;

void mf4 const;

};


class B{

public:

virtual void mf1();

virtual void mf2(unsigned int x);

virtual void mf3() &&;

void mf4 const;

};


B클래스는 A클래스를 상속받아 다음과 같은 함수들을 선언하였는데..


컴파일은 될까?


당연히 된다.


하지만, 여기서 프로그래머가 함수들을 재정의하려고 의도하였는지는 모르겠으나,


재정의가 되진 않았다.


아시다시피 앞서 설명한 재정의 규칙에 맞지 않기 때문이다.



class B{

public:

virtual void mf1() override;

virtual void mf2(unsigned int x) override;

virtual void mf3() && override;

void mf4 const override;

};

그렇다면 이렇게 override 라는 키워드를 붙여주면 어떨까?


컴파일러가 에러를 뿜어준다.


이것이 override 를 사용하는 이유이다.


멤버함수를 재정의하겠다는 프로그래머의 의도를 컴파일러가 지적해 주는 역할을 한다.



결론이다.


Base 클래스의 가상 함수를 재정의하려는 의도를 가진 멤버함수를


파생 클래스 안에서 선언할 때에는 그 함수를 반드시 override 로 선언하라