728x90

황기태 저자의 명품 C++ Programming 개정판을 읽고 학습한 내용을 정리한 포스트입니다!

https://search.shopping.naver.com/book/catalog/32436115747

 

C++ Programming : 네이버 도서

네이버 도서 상세정보를 제공합니다.

search.shopping.naver.com

 

가상 함수는 파생 클래스에서 오버라이딩할 함수를 알려주는 인터페이스의 역할을 한다. 응용 사례를 다루며 아래 4가지 주제에 대해 알아보자.

  • 가상 함수를 가진 기본 클래스의 목적
  • 가상 함수 오버라이딩
  • 동적 바인딩 실행
  • 기본 클래스의 포인터 활용

가상 함수를 가진 기본 클래스의 목적

  • Shape은 Circle, Rect, Line 등 도형의 공통 속성을 구현하는 기본 클래스의 역할을 한다.
  • Shape은 가상 함수 draw()를 선언하여, 파생 클래스에서 draw()를 오버라이딩하여 자신의 도형을 그리도록 유도한다.
  • 즉, 구체적인 도형을 묘사하지 않는 Shape 클래스는 Shape 객체를 생성하려는 의도로 만들어진 것은 아니다.

 

가상 함수 오버라이딩 : 파생 클래스마다 다르게 구현하는 다형성

  • 파생 클래스들은 가상 함수인 draw() 함수를 오버라이딩 함으로써 어떤 경우에도 자신이 만든 draw() 함수가 호출되는 것을 보장받는다.
  • 또한, Circle, Rect, Line이 draw() 함수를 다음과 같이 다르게 구현한다는 점에 주목해보자.
void Circle::draw() {
	cout << "Circle" << endl;
}


void Line::draw() {
	cout << "Line" << endl;
}

void Rect::draw() {
	cout << "Rectangle" << endl;
}

 


 

동적 바인딩 실행 : 파생 클래스의 가상 함수 실행

  • Circle, Rect, Line 클래스를 활용하여 원, 사각형, 선 등의 도형을 생성하고 이들을 링크드 리스트로 연결하여 관리하는 코드를 작성해보자.
  • main() 함수는 Circle, Rect, Line, Rect 객체를 순서대로 생성하여 링크드 리스트로 연결한다.
  • pStart 포인터가 처음 객체를, pLast 포인터가 마지막 객체를 가리킨다.
#include <iostream>
#include "Shape.h"
#include "Circle.h"
#include "Rect.h"
#include "Line.h"
using namespace std;

int main() {
	Shape *pStart=NULL;
	Shape *pLast;

	pStart = new Circle(); // 처음에 원 도형을 생성한다.
	pLast = pStart;

	pLast = pLast->add(new Rect()); // 사각형 객체 생성
	pLast = pLast->add(new Circle()); // 원 객체 생성
	pLast = pLast->add(new Line()); // 선 객체 생성
	pLast = pLast->add(new Rect()); // 사각형 객체 생성

	// 현재 연결된 모든 도형을 화면에 그린다.
	Shape* p = pStart;
	while(p != NULL) {
		p->paint();
		p = p->getNext();
	}

	// 현재 연결된 모든 도형을 삭제한다.
	p = pStart;
	while(p != NULL) {
		Shape* q = p->getNext(); // 다음 도형 주소 기억
		delete p; // 기본 클래스의 가상 소멸자 호출
		p = q; // 다음 도형 주소를 p에 저장
	}
}

/*
Circle
Rectangle
Circle
Line
Rectangle
*/
  • 동적 바인딩이 가장 화려하게 꽃피는 곳은 바로 다음 코드이다.
  • Shape 타입의 포인터 p를 이용하여 모든 도형을 방문하며 paint() 함수를 호출하면, paint()는 동적 바인딩을 통해 Circle, Rect, Line 클래스에 재정의된 각 draw() 함수를 호출한다.
// 현재 연결된 모든 도형을 화면에 그린다.
Shape* p = pStart;
while(p != NULL) {
	p->paint();
	p = p->getNext();
}


 

기본 클래스의 포인터 활용

  • 또 하나 유의해서 볼 부분은 pStart, pLast, p의 타입이다.
  • 모두 기본 클래스 Shape에 대한 포인터이다.
  • 따라서 pLast는 Shape를 상속받은 어떤 객체든지 가리킬 수 있으므로, 링크드 리스트를 따라 이동하면서 파생 클래스의 객체들을 삽입할 수 있다.
  • p의 경우 링크드 리스트를 따라 이동하면서 Shape의 paint()를 호출하여, 동적 바인딩으로 각 파생 클래스의 draw()를 호출하는 상황을 만들어낸다.

 

728x90

'Programming Language > C++' 카테고리의 다른 글

[C++] 템플릿  (0) 2023.12.19
[C++] 추상 클래스  (1) 2023.12.19
[C++] 오버라이딩  (0) 2023.12.18
[C++] 가상 함수와 오버라이딩  (1) 2023.12.18
[C++] 다중 상속과 가상 상속  (0) 2023.12.15