C++ 상속 공부

박동현·2020년 12월 1일
0

C++공부

목록 보기
1/6

C++ 상속과 virtual

class Super
{
	public:
    		void go() { cout<<"go() called on Super"<<endl; }
};

class Sub : public Super
{
	public:
    		void go() { cout<<"go() called on Sub"<<endl; }
};

Sub mySub;
mySub.go();

위 코드의 실행 결과는 'go() called on Sub' 이다.
하지만 이는 오버라이딩된 것이 아닌 Super의 go()와는 완전 별개인 새로운 메소드 go()를 정의한 것 이다.

Sub mySub;
Super& ref = mySub;
ref.go();

위 코드의 실행 결과는 'go() called on Super'가 출력된다.
ref는 Super의 참조형이기 때문에 go()는 Super의 go()가 호출된다.
따라서 오버라이딩 여부를 따지기 위해선 virtual 키워드를 사용해야 한다.

// 올바른 사용 예시
class Super
{
	public:
    		virtual void go() { cout<<"go() called on Super"<<endl; }
};

class Sub : public Super
{
	public:
    		//부모 클래스에서 이미 virtual로 선언했기 때문에
            	//자식 클래스에서는 자동으로 virtual이 적용
    		void go() { cout<<"go() called on Sub"<<endl; }
};

vitrual 성능

virtual은 활용에 따라 더 유연한 설계를 도와주지만 vtable을 사용하기 때문에 런타임에 어떤 함수를 호출할지 선택하는 기능이 포함되어 있다는 점에서 non-virtual 함수 호출보다 느리다.

최근 CPU는 vtable 호출의 오버헤드가 나노초 이하의 작은 단위로 측정되고 있어 소멸자를 포함한 모든 메소드(final 클래스 제외)를 virtual로 선언해야한다고 주장하는 사람도 있다. virtual최적화는 다음에 작성해보겠다.

static 메소드 상속

자식 클래스에서 부모 클래스에 있는 static 메소드와 같은 이름의 메소드를 정의하면 두 개의 서로 다른 메소드가 만들어 진다.

Sub subStatic;
Super& ref = subStatic;
ref.static();

위의 코드 결과는 Super객체의 static()이 호출된다. 이유는 C++에서는 객체가 무엇이든 관계없이 접근하는 타입에 맞추어 호출할 static메서드를 결정하기 때문이다.

protected, private 메소드

private로 선언된 메소드는 자식 클래스에서 접근할 수 없지만 오버라이딩할 수 는 있다. C#과 자바에서는 private 메소드 오버라이딩은 할 수 없다.

class MilesEstimator
{
public:
	virtual int getMilesLeft() const { 
    		return getMilesPerGallon() * getGallonesLeft();
	}
	virtual void setGallonsLeft(int value) { gallonsLeft = value; }
	vitrual int getGallonsLeft() const { return gallonsLeft; }
private:
	int gallonsLeft;
    //연비
	vitual int getMilesPerGallon() { return 20; }    
};

getMilesLeft()함수는 milesPerGallon과 GallonLeft의 곱에 의해 결정된다.
다음과 같이 사용할 수 있다.

MilesEstimator estimator;
estimator.setGallonsLeft(2); //남은 연료
cout <<"I can go "<< estimator.getMilesLeft() << " more miles." <<endl;

실행결과는

I can go 40 more miles

getMilesPerGallon()를 오버라이딩하여 다음과 같이 사용 할 수 있다.

class SubMilesEstimator : public MilesEstimator
{
	...
    	private:
    	int getMilesPerGallon() = override { return 35; }
};

SubMilesEstimator subEstimator;
subEstimator.setGallonsLeft(2); //남은 연료
cout <<"I can go "<< estimator.getMilesLeft() << " more miles." <<endl;

실행결과는

I can go 70 more miles

따라서 전반적인 변경이 필요하지 않고 특정 속성만 바꾸면 될 때 private, protected 메서드를 오버라이딩 하는 방법도 있다.

참고자료 : professional c++ 3rd edition

profile
엔진 프로그래머를 목표로합니다.

0개의 댓글