안녕하세요~
이번에는 오버라이딩을 공부했지만, 어떻게 쓰이는 지 이해가 잘 안되시는 분들을 위해 예제로 통해 쉽게 설명드리고 싶어 글을 쓰게 되었습니다. 오버라이딩을 했을 때와 안했을 때 예시를 통해 코드가 어떻게 다른지도 밑에 있으니 공부에 참고하시면 좋을 것 같습니다.
오버라이딩을 통해 다형성을 실현한 예시
#include <iostream>
using namespace std;
class Shape
{
public:
Shape() {}
~Shape() {}
virtual void Draw() = 0;
private:
};
class Circle : public Shape{
public:
Circle(){}
~Circle() {}
void Draw(){ cout << "Circle drawing routine here!\n"; }
};
class Rectangle : public Shape
{
public:
Rectangle(){}
virtual ~Rectangle() {}
virtual void Draw(){ cout << "Rectangle drawing routine here!\n"; }
};
class Triangle : public Shape{
public:
Triangle();
~Triangle() { }
void Draw(){ cout << "Triangle drawing routine here!\n"; }
};
int main()
{
int choice;
bool fQuit = false;
Shape* sp = nullptr;
while (!fQuit) {
cout << "(1)Circle (2)Rect (3)Triangle (0)Quit: ";
cin >> choice;
switch (choice) {
case 0: fQuit = true;
break;
case 1: sp = new Circle;
break;
case 2: sp = new Rectangle;
break;
case 3: sp = new Triangle;
break;
default: cout << "Please enter a number(0~3)\n";
continue; break;
}
if (!fQuit) {
sp->Draw();
delete sp; sp = 0; cout << "\n";
}
}
return 0;
}
이 예제에서 주목해야할 것은 switch문에서 업캐스팅을 통해 다른 객체의 자유기억공간을 생성한 후, sp->Draw()로 다형성을 실현한 것입니다.
만약 오버라이딩을 하지 않았다면 코드를 다음과 같이 구현해야합니다.
#include<iostream>
using namespace std;
class Shape
{
public:
Shape() {}
~Shape() {}
virtual void Draw() = 0;
private:
};
class Circle : public Shape
{
public:
Circle() {}
~Circle() {}
void Draw(){ cout << "Circle drawing routine here!\n"; }
};
class Rectangle : public Shape
{
public:
Rectangle() {}
virtual ~Rectangle() {}
virtual void Draw() { cout << "Rectangle drawing routine here!\n"; }
};
class Triangle : public Shape{
public:
Triangle() {}
~Triangle() {}
void Draw() { cout << "Triangle drawing routine here!\n"; }
};
int main()
{
int choice;
bool fQuit = false;
Circle* c = nullptr;
Rectangle* r = nullptr;
Triangle* t = nullptr;
while (!fQuit) {
cout << "(1)Circle (2)Rect (3)Triangle (0)Quit: ";
cin >> choice;
switch (choice) {
case 0: fQuit = true;
break;
case 1: //sp = new Circle(5);
c = new Circle;
break;
case 2: //sp = new Rectangle(4, 6);
r = new Rectangle;
break;
case 3: //sp = new Square(5);
t = new Triangle;
break;
default: cout << "Please enter a number(0~3)\n";
continue; break;
}
if (!fQuit) {
switch (choice) {
case 1:
c->Draw();
break;
case 2:
r->Draw();
break;
case 3:
t->Draw();
break;
}
switch (choice) {
case 1:
delete c;
c = 0;
break;
case 2:
delete r;
r = 0;
break;
case 3:
delete t;
t = 0;
break;
}
cout << "\n";
}
}
return 0;
}
Draw() 함수를 호출할 때도, 할당한 자유기억공간을 해제할 때도 전부 switch문을 통해 해야하므로 코드의 길이가 길어집니다.
오버라이딩을 통한 다형성 실현 예시를 조금 더 상세하게 설명하기 위해 필수 개념인 업캐스팅, 가상함수, 오버라이딩 대해서 짚고 넘어가겠습니다.
업캐스팅(Upcasting)
업캐스팅이란 기본 클래스의 포인터로 파생 클래스 객체의 주소를 가리키는 것을 말합니다.
파생클래스는 기본클래스의 멤버를 모두 상속받기 때문에 가능한 것입니다.
예를 들어, 음악이라는 기본클래스가 있다고 칩시다. 멤버로는 선율, 리듬, 화음이 있습니다. 파생클래스는 클래식, 발라드, 락 등이 있습니다. 클래식, 발라드, 락에는 음악의 3요소인 선율, 리듬, 화음이 모두 있고 우리는 당연하게도 이들을 음악이라고 합니다. (우리는 업캐스팅을 늘 해오던 것이었습니다!!)
가상함수(Virtual function)
가상함수의 정의가 뭐냐!! 라고 물으면 "Virtual 붙인거"라고 대답하는 것이 아니라,
"컴파일 할 때 하는 함수 바인딩 작업을 실행할 때로 미루는 키워드"라고 대답해야합니다.
오버라이딩(Overriding)
오버라이딩이란 함수 재정의 + virtual함수라고 생각하시면 됩니다.
즉, 파생클래스에서 기본클래스로부터 상속받은 멤버함수를 재정의하고, 기본클래스의 함수에 virtual키워드를 붙이면 이는 오버라이딩을 한 것입니다.
오버라이딩을 함으로써 동적바인딩이 어떻게 이루어지는 지 위의 예시를 통해 살펴보겠습니다.
조금 더 자세하게 들어가면 가상함수테이블이 있고 함수의 주소가 그 안에 들어가는 걸로 아는 데 저는 저런 식으로 생각하니까 이해하기 쉽더라구요.
이렇게 오버라이딩을 하면 함수재정의를 했을 때 처럼 포인터변수의 형을 보고 호출함수를 정적으로 바인딩하는 것이 아니라, 포인터변수가 가리키는 자유기억공간의 형을 보고 함수를 동적으로 바인딩합니다.
그래서 더 간결한 코드를 작성할 수 있죠.
'Programming > C,C++' 카테고리의 다른 글
[C,C++] Inheritance and Type Casting (0) | 2025.10.10 |
---|---|
[C, C++] Make (1) | 2025.10.10 |
참조리턴 (0) | 2022.02.23 |
복사생성자 (0) | 2022.02.23 |
연산자 중복 (0) | 2022.02.22 |