게임 개발/C++

[C++] 오버라이딩 - 1. 정적 & 동적

유행성바코드 2025. 2. 24. 20:19

목차

  • 01. Intro
  • 02. 오버라이딩
    • 정적 오버라이딩
    • 동적 오버라이딩
  • 03. 마무리
  • 04. 연관 내용

01. Intro

오늘은 클래스를 상속받았을 때, 사용할 수 있는 함수 오버라이딩에 대해 알아보겠습니다.

 


02. 오버라이딩

오버라이딩이란?

부모 클래스로부터 상속받은 함수를 자식 클래스에서 다시 재정의하는 것을 말합니다.

 

재정의할 때는 반드시 부모 클래스의 함수명과 매개 변수 개수 및 타입이 일치해야 합니다.

단, 매개 변수 이름은 서로 달라도 상관없습니다.

 

아래 예시 코드를 바탕으로 한 번 알아보겠습니다.

#include <iostream>

using namespace std;

class A
{
public:
	void AddX() { _x += 20; }
	
	int _x = 10;
};

class B : public A
{
public:
	void AddX() { _x += 40; }
};

int main()
{
	A a;
	B b;

	a.AddX();
	b.AddX();

	cout << a._x << "\n";
	cout << b._x << "\n";
}

 

코드에 대한 상황은 아래와 같습니다.

 

1. B클래스는 A클래스를 상속받고 있습니다.

2. B클래스에서는 A클래스의 AddX() 함수를 재정의(오버라이딩) 하고 있습니다.

3. 클래스 A에 대한 객체 a, 클래스 B에 대한 객체 b를 생성하고 각 객체는 AddX() 함수를 호출했습니다.

4. 그에 대한 결과는 아래 사진과 같이 나옵니다.

 

이렇게 함수를 재정의할 경우, 재정의한 함수가 실행되는 것을 확인했습니다.

 

추가로 재정의하는 방식인 정적 오버라이딩(Static Overriding)동적 오버라이딩(Dynamic Overriding)을 알아보겠습니다. 

 

정적 오버라이딩

정적 오버라이딩은 정적 바인딩(Static Binding)으로 컴파일 타임에 함수의 실행 클래스가 결정됩니다.

특징으로는 현재 객체의 클래스 타입에 따라 호출되는 함수가 결정됩니다.

 

아래 예시 코드를 바탕으로 한 번 살펴보겠습니다.

#include <iostream>

using namespace std;

class A
{
public:
	void AddX() { _x += 20; }
	
	int _x = 10;
};

class B : public A
{
public:
	void AddX() { _x += 40; }
};

int main()
{
	B b;

	A* a = &b;

	a->AddX();

	cout << a->_x << "\n";
}

 

실행 결과는 아래 사진과 같습니다.

 

B클래스에 대한 객체 b를 생성했지만, A클래스의 포인터 a가 객체 b의 주소를 가리키도록 했습니다.

그 후, 포인터 a에서 AddX() 함수를 호출했습니다.

 

포인터 a는 현재 자신이 가리키고 있는 객체를 클래스 A라고 생각합니다.

또한, 정적 오버라이딩이므로 컴파일 타임에 클래스 A의 AddX() 함수가 호출된다고 결정되어 있습니다.

이러한 결과로 인해 멤버 변수인 _x에 20의 값만 더해져서 30의 출력값을 갖게 됩니다.

 

동적 오버라이딩

동적 오버라이딩은 런타임 즉, 실행 타임에 함수의 실행 클래스가 결정됩니다.

virtual 키워드를 사용해 함수를 가상 함수로 만들면, 동적 오버라이딩이 적용됩니다.

특징으로는 현재 객체의 클래스 타입이 아닌 객체의 원본 클래스 타입에 따라 호출되는 함수가 결정됩니다.

 

아래 예시 코드를 바탕으로 한 번 살펴보겠습니다.

#include <iostream>

using namespace std;

class A
{
public:
	virtual void AddX() { _x += 20; }
	
	int _x = 10;
};

class B : public A
{
public:
	virtual void AddX() { _x += 40; }
};

int main()
{
	B b;

	A* a = &b;

	a->AddX();

	cout << a->_x << "\n";
}

 

실행 결과는 아래 사진과 같습니다.

 

정적 오버라이딩에서의 예시 코드처럼 작성했습니다.

다만, AddX() 함수 앞에 virtual 키워드를 붙여 함수를 가상화했습니다.

 

여기서도 정적 오버라이딩과 마찬가지로 포인터 a는 현재 자신이 가리키고 있는 객체를 클래스 A라고 생각합니다.

하지만, 동적 오버라이딩은 런타임(실행 타임)에 호출할 함수가 결정되는데 원본의 클래스를 따라갑니다.

그래서 클래스 A의 포인터지만, 원본인 클래스 B의 AddX() 함수가 호출됩니다.

이러한 결과로 인해 멤버 변수인 _x에 40의 값만 더해져서 50의 출력값을 갖게 됩니다.

 

동적 오버라이딩이 가능한 이유는 가상 함수 테이블과 가상 함수 테이블 포인터가 원본 클래스의 함수 주소를 가리키기 때문에 가능합니다. 가상 함수 테이블과 가상 함수 테이블 포인터가 어떻게 동작해서 해당 결과가 나올 수 있는지는 추후에 알아보도록 하겠습니다.

 

가상 함수 사용 예시

가상 함수는 같은 부모 클래스를 상속받은 객체들끼리 관리하기 편합니다.

따라서, 아래 예시처럼 사용할 수 있습니다.

#include <iostream>

using namespace std;

class Sport
{
public:
	virtual void Play() const
	{
		cout << "Sport Game Start!" << endl;
	}
};

// Sport 클래스를 상속 받는 Soccer 클래스
class Soccer : public Sport
{
public:
	virtual void Play() const
	{
		cout << "Soccer Game Start!" << endl;
	}
};

// Sport 클래스를 상속 받는 Baseball 클래스
class Baseball : public Sport
{
public:
	virtual void Play() const
	{
		cout << "Baseball Game Start!" << endl;
	}
};

int main()
{
	// Soccer 객체와 Baseball 객체를 만들고 각 객체의 주소값을 담는 포인터 생성
	Soccer* soccer = new Soccer();
	Baseball* baseball = new Baseball();

	// soccer 주소값과 baseball 주소값을 Sport 클래스 주소값에 담기
	Sport* sports[2];
	sports[0] = soccer;
	sports[1] = baseball;

	// sports 주소값이 가리키는 객체에 대해서 Play 가상 함수 호출
	for (const Sport* sport : sports)
	{
		sport->Play();
	}
}

 

아래 사진은 실행 결과입니다.

 

Soccer 클래스와 Baseball 클래스는 서로 다른 클래스입니다.

하지만, 같은 부모 클래스인 Sport를 상속받았습니다.

그래서, 부모 클래스의 포인터에 같이 담고 부모 클래스의 가상 함수인 Play()를 호출해

각 자식 클래스의 가상 함수가 실행되도록 할 수 있습니다.

 

이렇게, 같은 부모 클래스를 상속받은 서로 다른 클래스의 객체를 관리하는데 유용하게 활용할 수 있습니다.

 


03. 마무리

티스토리에서 제공해 주는 코드 블럭을 처음 사용했는데 너무 편하네요.

앞으로도 코드 관련 내용을 작성할 때는 활용해야겠습니다. 

이를 바탕으로 추후에는 가상 함수 테이블과 순수 가상 함수 등에서 다뤄보도록 하겠습니다.

 


04. 연관 내용

  • [C++] 오버라이딩 - 2. 가상 함수 테이블 및 가상 함수 테이블 포인터 
 

[C++] 오버라이딩 - 2. 가상 함수 테이블 & 포인터

목차01. Intro02. 가상 함수가상 함수 테이블 포인터가상 함수 테이블 03. 마무리04. 연관 내용01. Intro지난 시간에 오버라이딩 종류인 [정적 오버라이딩]과 [동적 오버라이딩]에 대해서 알아봤습니다

epidemic-barcode.tistory.com

  • [C++] 오버라이딩 - 3. 순수 가상 함수 및 추상 클래스
 

[C++] 오버라이딩 - 3. 순수 가상 함수

목차01. Intro02. 가상 함수 호출 과정 복습03. 순수 가상 함수정의 및 형태특징추상 클래스03. 마무리04. 연관 내용01. Intro지난 시간에 동적 오버라이딩인 가상 함수를 적용했을 때, 어떤 과정으로 동

epidemic-barcode.tistory.com

 

 


 

읽어주셔서 감사합니다.

틀린 내용 지적은 언제나 환영입니다!