본문 바로가기
C++

[C++] 객체지향과 클래스에 대해 - 상속(Inheritance)

by rehtorb_s 2020. 6. 20.

앞선 포스팅의 접근지정자 public, private을 캡슐화(Encapsulation)과 함께 설명했는데요. 오늘 포스팅은 나머지 하나. protected에 대해 설명하겠습니다. 

 

근데 protected를 이해하기 전에 상속(Inheritance)이란 개념을 반드시 알고 넘어가야 합니다. 상속은 객체지향 특성 4가지 중 하나로, 나머지 특성이면서 가히 C++의 꽃이라 할 수 있는 다형성(Polymorphism) 실현에 필수적인 요소이기 때문입니다. 뿐만 아니라 클래스 간의 계층적 분류를 통해 관리 및 재사용을 용이하게 할 수 있는데 이는 소프트웨어의 생산성을 향상시킬 수 있습니다.

 

상속이란 클래스를 정의할 때 어떤 클래스를 확장하여 파생하는 걸 말합니다. 그러면 기본클래스(부모클래스), 파생클래스(자식클래스)의 관계가 성립되면서 파생클래스는 기본클래스의 기능을 포함하게 됩니다.

 

 

 

 

 

 

 

 

시대가 지나면서 통신속도가 비약적으로 상승함에 따라 모바일핸드폰의 세대를 계층적으로 나눌 수 있습니다. 

CMobilePhone : 전화

2G Phone : 전화, 문자, 카메라

3G Phone : 전화, 문자, 카메라, 유심, 인터넷

Smart Phone : 전화, 문자, 카메라, 유심, 인터넷 및 수많은 기능들

 

한눈에 보기 위한 자료첨부~

 

 

 

 

 

 

파생클래스가 기본클래스 속성을 포함하면서 본인만의 속성을 가지는 모습(확장)입니다. 진화에 진화를 거듭하고 있네요. 그렇다면 접근지정자 protected와 상속이 무슨 연관성이 있을까요?

 

"public 멤버는 어디서든 누구나 접근이 가능하다, private 멤버는 해당 멤버를 선언한 해당 클래스 내에서만 접근이 가능하다"

 

누구나 접근하면 뭔가 꺼림칙하고 그렇다고 아무도 접근을 못하게 한다면 그건 너무 야박하잖아요?

그래서 서로 연관있는 상속 관계의 파생클래스 내부에서는 접근할수 있도록 권한을 주는게 protected입니다. 캡슐화의 유연성이라고 해야할까요. 어찌됐건 상속성에 날개를 달아주는 것 같습니다. 그럼 어떤 속성을 protected에 선언을 할까요? 업무프로세스에 따라, 사람에 따라 내용은 다르겠지만 대개 기본클래스, 파생클래스가 내부적으로 공통으로 사용하는 속성을 선언합니다.

 

위 내용에는 없지만 메모리를 예로 들어봅시다. 모든 핸드폰에는 메모리가 존재하지만 용량이 다르죠. 물론 메모리도 세대에 따라 하드웨어 스펙이 다르긴 하지만 용량만 놓고 봤을 때 스마트폰이 쓰기엔 2G폰 메모리량은 턱없이 부족하죠. 

 

동일한 맥락에서 MobilePhone과 2GPhone 클래스에 대한 코드 예제를 보겠습니다. (포스팅 가독성을 위해 헤더파일에 선언과 정의를 동시에 했습니다)

 

2G 폰에는 문자와 카메라 데이터 때문에 메모리에 접근할 일이 더 많아졌습니다. 

//CMobilePhone.h
class CMobilePhone
{
public:
	void Call() { std::cout << "전화하다" << std::endl; }		//전화기능
	void SetMemory(int value) { m_memory = value; }			//메모리셋
	int GetMemory() { return m_memory; }				//메모리반환
protected:
	int m_memory;
};


//C2GPhone.h
class C2GPhone : public CMobilePhone
{
public:
	//문자를 저장할때마다 1씩 감소
	void Message() { m_memory = m_memory - 1; } 
    
	//사진데이터를 저장할 때마다 10씩 감소
	void Camera() { m_memory = m_memory - 10; }	
};

//main.cpp
int main(void)
{
	C2GPhone phone2G;					//객체생성
	phone2G.SetMemory(1024);				//메모리 셋
	
	phone2G.Message();					//문자사용, 메모리감소
	phone2G.Camera();					//카메라사용, 메모리감소
	std::cout << phone2G.GetMemory() << std::endl;		//남은 메모리 출력

	return 0;
}

 

 

 

 

 

 


현재 메모리에 할당된 phone2G 객체를 단순 시각화 시킨다면 아래의 구조를 가집니다. 상속은 파생클래스가 기본클래스의 속성을 포함하면서 자신의 속성을 가진다고 설명했는데 이를 파생클래스 객체가 기본클래스의 멤버를 자기멤버로 가지는 걸로 오해하시는 분들도 있습니다. 정확히 하자면 파생클래스 객체는 각각의 클래스 영역을 구분해서 지니고 있어요. 이 부분에 대해 클래스 접근지정자와 다형성, 업/다운 캐스팅에서 추가로 다루겠습니다.

 

 

 

 

 

 

 

 

다시 코드로 돌아와서.. 파생클래스에서 기본클래스의 protected 멤버에 접근할 수 있으니까... 아래같은 경우의 코드가 쉽게 떠오를? 수도 있는데

 

//main.cpp
int main(void)
{
	C2GPhone phone2G;
	phone2G.m_memory = 1024;		//파생클래스 객체가 멤버에 접근을 시도

	return 0;
}

안됩니다. 객체 phone2G가 파생클래스 타입이라 하더라도 main에서 선언된 외부변수이기 때문입니다. protected 멤버는 기본, 파생클래스 내부에서만 접근을 하거나 이전 포스팅 내용처럼 public 멤버함수를 선언해서 멤버변수에 대한 통제된 접근만 가능하다는 점 반드시 기억하셔야 합니다. 근데 이런 오류는 IDE가 알아서 걸러주긴 합니다 ㅎㅎ..

 

마지막으로 상속에서 주의할점

1. 상속관계의 클래스를 정의할 때는 각 클래스(기본, 파생)의 기능을 명확히 분류하자!

 => 이기능 저기능 짬뽕되다보면 어느새 상속의 의미는 퇴색하게 되며..(본인이 자주그럼) 알아보기 힘들게 됩니다.

2. 기본클래스의 기능을 사용하고자 상속을 무분별하게 한다면 말도안되는 혹은 비효율적인 코딩이된다.

 => 핸드폰에 디스플레이가 있다해서 TV가 핸드폰을 상속받을 수 없는것 처럼요. 

3. 다중상속에 주의하자

 =>

 

 

 

 

 

 

 

클래스D의 객체를 생성할 때 클래스A의 멤버를 중복으로 가지게 되는데 이 멤버에 접근을 하게 된다면 B에 속한 A멤버인지 C에 속한 A멤버인지 몰라서 모호성이 발생하게 됩니다.. 상속 관계에 있어 다이아몬드 형태를 주의 합시다. (단 virtual 키워드로 상속을 받으면 해결된다고 한다. 추후 다형성에서 설명)

 

이렇게 객체지향의 특징 중 하나인 상속에 대해서도 배웠습니다~!@ 다음 포스팅은 C++의 꽃 다형성(Polymorphism)에 대해 알아봅시다.

 


포스팅 내용에 오류가 있거나 지적사항이 있다면 댓글로 달아주세요. 배움을 멈추지 않는 Good Programmer가 되겠습니다. 감사합니다.

댓글