IS-A 관계의 성립
상속 관계가 성립하려면 기초 클래스와 유도 클래스 간의 IS - A 관계가 성립해야 한다.
예를들어,
- 무선 전화기 is a 전화기
- 노트북 컴퓨터 is a 컴퓨터
전화기와 컴퓨터의 기본 기능을 '통화'와 '계산'이라고 한다면, 무선 전화기와 노트북 컴퓨터는 기본 기능에 '이동성'이라는 특성이 추가되었다.
따라서 전화기와 컴퓨터를 기초 클래스, 무선 전화기와 노트북 컴퓨터를 유도 클래스로 정의할 수 있다.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class Computer {
private:
char owner[50];
public:
Computer(const char* name) {
strcpy(owner, name);
}
void Calculate() {
cout << "요청 내용을 계산합니다." << endl;
}
};
class NotebookComp : public Computer
{
private:
int Battery;
public:
NotebookComp(const char* name, int initChag)
:Computer(name),Battery(initChag)
{ }
void Charging() { Battery += 5; }
void UseBattery() { Battery -= 1; }
void MovingCal()
{
if (GetBatteryInfo() < 1) {
cout << "충전이 필요합니다." << endl;
return;
}
cout << "이동하면서 ";
Calculate();
UseBattery();
}
int GetBatteryInfo() { return Battery; }
};
class TabletNotebook : public NotebookComp
{
private:
char regstPenModel[50];
public:
TabletNotebook(const char* name, int initChag, const char* pen)
: NotebookComp(name, initChag)
{
strcpy(regstPenModel, pen);
}
void Write(const char* penInfo) {
if (GetBatteryInfo() < 1) {
cout << "충전이 필요합니다." << endl;
return;
}
if (strcmp(regstPenModel, penInfo) != 0)
{
cout << "등록된 펜이 아닙니다.";
return;
}
cout << "필기 내용을 처리합니다." << endl;
UseBattery();
}
};
int main() {
NotebookComp nc("이수종", 5);
TabletNotebook tn("정수영", 5, "ISE-241-242");
nc.MovingCal();
tn.Write("ISE-241-242");
return 0;
}
위 예제에서 TabletNotebook 클래스의 객체 생성 과정에서는 TabletNotebook 클래스가 상속하는 NotebookComp 클래스의 생성자와, Computer 클래스의 생성자가 모두 호출되며, 다음의 관계가 성립한다.
- NotebookComp is a Computer
- TabletNotebook is a Computer
- TabletNotebook is a Computer
위 예제의 클래스들의 관계를 UML으로 나타내면 다음과 같다.
위 그림에서 화살표는 상속을 의미하며, 화살표의 머리는 기초 클래스를 향한다.
HAS - A 관계도 상속의 조건은 되지만 복합 관계로 이를 대신하는것이 일반적이다.
HASInheritance.cpp
#include <iostream>
#include <cstring>
using namespace std;
class Gun
{
private:
int bullet; //장전된 총알의 수
public:
Gun(int bnum) : bullet(bnum)
{ }
void Shut()
{
cout << "BBANG!" << endl;
bullet--;
}
};
class Police : public Gun
{
private:
int handcuffs; //소유한 수갑의 수
public:
Police(int bnum, int bcuff)
:Gun(bnum), handcuffs(bcuff)
{ }
void PutHandcuff()
{
cout << "SNAP!" << endl;
handcuffs--;
}
};
int main(void) {
Police pman(5, 3);//총알 5, 수갑 3
pman.Shut();
pman.PutHandcuff();
return 0;
}
HASComposite.cpp
#include <iostream>
#include <cstring>
using namespace std;
class Gun
{
private:
int bullet;
public:
Gun(int bnum) : bullet(bnum)
{ }
void Shut()
{
cout << "BBANG!" << endl;
bullet--;
}
};
class Police
{
private:
int handcuffs;
Gun* pistol;//소유하고 있는 권총
public:
Police(int bnum, int bcuff)
:handcuffs(bcuff)
{
if (bnum > 0)
pistol = new Gun(bnum);
else
pistol = NULL;
}
void PutHandcuff() {
cout << "SNAP!" << endl;
handcuffs--;
}
void Shut() {
if (pistol == NULL)
cout << "Hut BBang!" << endl;
else
pistol->Shut();
}
~Police() {
if (pistol != NULL)
delete pistol;
}
};
int main(void) {
Police pman1(5, 3);
pman1.Shut();
pman1.PutHandcuff();
Police pman2(0, 3); //권총을 소유하지 않은 경찰
pman2.Shut();
pman2.PutHandcuff();
return 0;
}
HASInheritance.cpp를 1번 코드, HASComposite.cpp를 2번 코드라고 하겠다.
1번 코드에서는 권총을 소유하는 경찰을 표현하고 있다. (경찰 has a 총)
1번 코드와 같이 HAS - A 관계도 상속으로 표현할 수 있다.
그러나, 이러한 소유의 관계는 2번 코드와 같이 다른 방식으로도 얼마든지 표현이 가능하다.
상속으로 묶인 두 개의 클래스는 강한 연관성을 띤다.
1번 코드에서는 총을 소유한 경찰만 표현이 가능하지만, 2번 코드에서는 pistol을 NULL로 초기화 함으로써 권총을 소유하지 않은 경찰도 간단히 표현하였다.
그리고 만약 경찰이 전기봉을 소유하는 상황을 추가로 표현하려면
2번 코드에서는 전기봉을 소유하는 객체를 참조하는 멤버변수 하나만 추가하면 되지만,
1번 코드의 방식으로는 이를 처리하기가 복잡하다.
결론 :
상속은 IS-A 관계의 표현에 매우 적절하며,
HAS-A 관계의 표현에도 사용될 수는 있으나, 이는 프로그램의 변경에 많은 제약을 가져다 줄 수 있다.
'공부 > C++' 카테고리의 다른 글
[C++] 8-1. 객체 포인터의 참조 관계 (0) | 2024.11.11 |
---|---|
[C++] 7-5. OOP 단계별 프로젝트 05단계 (1) | 2024.11.10 |
[C++]7-3. protected 선언과 세가지 형태의 상속 (0) | 2024.11.07 |
[C++] 7-2. 상속의 문법적인 이해 (0) | 2024.11.06 |
[C++] 7-1. 상속에 들어가기에 앞서 (0) | 2024.11.06 |