본문 바로가기

C++

[C++] 상속(Inheritance)

상속이란?

 

상속(Inheritance)은 객체 단위 코드를 재사용하는 방법이며, 이러한 재사용을 통해 기능적 확장이나 개선을 할 수 있다.

 

 

기본 작성 문법은 다음과 같다.

 

class 클래스이름 : 접근제어지시자 부모클래스이름

 

 

예제 코드를 통해서 상속을 어떻게 사용하고 어떤 식으로 동작하는지 알아보자.

 

#include <iostream>
using namespace std;

//부모클래스
class PClass
{
public:
	PClass() { cout << "PClass()" << endl; }
	int getNum() { return num; }
	void setNum(int param) { num = param; }

protected:
	void printNum() { cout << "printNum" << endl; }

private:
	int num = 0;
};

//파생클래스
class CClass : public PClass
{
public:
	CClass() { cout << "CClass()" << endl; }
	void TestFunc()
	{
		printNum();	//PClass::printNum()과 동일
		setNum(100);	//PClass::setNum(100)과 동일
		cout << PClass::getNum() << endl;
	}
};

int main()
{
	CClass a;	//파생클래스 객체 생성

	a.setNum(10);
	cout << a.getNum() << endl;

	a.TestFunc();

	return 0;
}

 

결과값:

PClass()
CClass()
10
printNum
100

 

결과값을 통해서 다음을 알 수 있다.

 

1. 파생 클래스의 인스턴스가 생성될 때 부모 클래스의 생성자도 자동으로 호출된다.

2. 파생 클래스는 private를 제외한 public, protected 접근 제어 지시자로 선언된 클래스 멤버에 접근할 수 있다.

3. 파생 클래스의 인스턴스를 통해 기본 클래스 메서드를 호출할 수 있다.

 

파생 클래스의 객체를 통해 부모 클래스의 printNum() 함수를 호출하였다. 또한, printNum() 함수는 protected 접근 제어 지시자로 선언되었지만 상속관계에서는 접근이 허용된다.

 

파생 클래스 객체를 생성하자 파생 클래스의 생성자 CClass() 뿐만 아니라 부모 클래스 생성자 PClass()도 호출되었다. 파생 클래스의 생성자가 먼저 호출되지만 파생 클래스 생성자는 부모 클래스의 생성자를 호출하면서 부모 클래스의 생성자가 먼저 생성된다.

 

반면, 소멸자 호출은 반대가 되어 생성자와 소멸자의 호출 순서는 다음과 같다.

 

PClass()
CClass()
~CClass()
~PClass()

 

따라서 다음과 같은 상황은 조심해야 한다.

 

#include <iostream>
using namespace std;

//부모클래스
class PClass
{
public:
	PClass()
	{
		ptr = new char[10];
	}
	~PClass()
	{
		delete ptr;	//멤버 메모리 해제
	}

protected:
	char* ptr;
};

//파생클래스
class CClass : public PClass
{
public:
	CClass() {}
	~CClass()
	{
		delete ptr;	//파생 클래스에서 부모 클래스 멤버 메모리 해제
	}
};

int main()
{
	CClass a;

	return 0;
}

 

결과값:

에러, 프로그램종료

 

소멸자는 파생 클래스가 먼저 생성되어 파생 클래스에서 부모 클래스 멤버 메모리를 이미 해제했기 때문에 부모 클래스 소멸자에서 또 해제하는 과정에서 에러가 발생한다.

 

따라서 생성자와 소멸자는 객체 자신의 초기화 및 해제만 다루도록 하는 것이 좋다. 특히 포인터라면 더욱 그렇다.