도순씨의 코딩일지
C++ :: protected 상속, private 상속, IS-A 관계, HAS-A 관계 본문
🌼 protected 선언
C++의 접근제어 지시자에는 private, protected, public 이렇게 세 가지가 있습니다. 이들이 허용하는 범위는 다음과 같습니다.
private < protected < public
public이 허용하는 범위가 가장 넓고, private가 허용하는 접근 범위가 가장 좁습니다. protected는 private와 매우 유사하지만 차이점이 있습니다. protected의 이해를 위해서 다음 클래스를 살펴봅시다.
1
2
3
4
5
6
7
8
9
10
11
|
class Base{
private:
int num1;
protected:
int num2;
public:
int num3;
void ShowData(){
cout << num1 << ", " << num2 << ", " << num3;
}
};
|
cs |
멤버변수 num1은 private로 선언되어 있고, num2는 protected로 선언되어 있습니다. 이러한 상태에서는 큰 차이가 없습니다. 하지만 상속이 된다면 달라질 수 있습니다. 어떻게 달라질까요?
1
2
3
4
5
6
7
8
|
class Derived : public Base{
public:
void ShowBaseMember(){
cout << num1;
cout << num2;
cout << num3;
}
};
|
cs |
위 코드는 Base 클래스를 상속하고 있습니다. public으로 선언된 멤버변수 num3에 접근이 가능하지만 private로 선언된 멤버변수 num1에는 접근이 불가능합니다. protected로 선언된 멤버변수는 이를 상속하는 유도 클래스에서 접근이 가능합니다. 하지만 기초 클래스와 이를 상속하는 유도 클래스 사이에서도 '정보은닉'은 지켜지는 것이 좋습니다.
🌼 protected 선언
1
2
3
4
5
6
7
8
|
class Base{
private:
int num1;
protected:
int num2;
public:
int num3;
};
|
cs |
이 클래스를 protected로 상속해보면 다음과 같습니다.
1
2
3
|
class Derived : protected Base{
// empty!
};
|
cs |
위의 코드는 protected보다 접근의 범위가 넓은 멤버는 protected로 변경시켜서 상속한다는 의미를 가지고 있습니다. 하지만 이는 잘못 표현된 것입니다. 아래 코드를 한 번 살펴봅시다.
⭐️ ProtectedHeri.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <iostream>
using namespace std;
class Base{
private:
int num1;
protected:
int num2;
public:
int num3;
Base() : num1(1), num2(2), num3(3) {}
};
class Derived : protected Base {} ;
int main(void){
Derived drv;
cout << drv.num3 << endl;
return 0;
}
|
cs |
19번째 라인에서 컴파일 오류가 발생합니다. 이는 Base 클래스를 protected로 상속했기 때문입니다. protected로 상속했기 때문에 public 멤버변수인 num3는 Derived 클래스에서 protected 멤버가 되고 외부에서는 접근이 불가능해졌습니다.
🌼 private 상속
앞서 정의한 Base 클래스를 참고하여 봅시다. 이 클래스를 private로 상속한다면 어떻게 될까요? 클래스를 private으로 상속해보겠습니다.
1
2
3
|
class Derived : private Base {
// empty!
};
|
cs |
위 코드가 의미하는 바는, private보다 접근 범위가 넓은 멤버는 private으로 변경시켜서 상속하겠다는 것입니다. 하지만 이러한 경우, 멤버 함수를 포함하여 모든 멤버가 접근 불가가 되기 때문에 의미없는 상속이 되고 맙니다.
🌼 private 상속
public 상속은 public보다 접근의 범위가 넓은 멤버를 public으로 변경시켜서 상속하는 것입니다. C++에서는 public 상속을 제외하고는 거의 존재하지 않습니다.
🌼 상속을 위한 기본 조건 :: IS-A
상속의 기본 문법에서 보이듯이, 유도 클래스는 기초 클래스가 지니는 모든 것을 가지고 거기에 유도 클래스만의 특성이 더해지는 체계입니다.
IS-A는 '일종의 ~이다'라고 해석하면 됩니다. 상속관계가 성립하려면 기초 클래스와 유도 클래스 간에 IS-A 관계가 성립해야 합니다. 예제를 한 번 살펴봅시다.
⭐️ISAInheritance.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
#include <iostream>
#include <cstring>
using namespace std;
class Computer{
private:
char owner[50];
public:
Computer(char * name){
strcpy(owner, name);
}
void Calculate(){
cout << "요청 내용을 계산합니다."<< endl;
}
};
class NotebookComp : public Computer{
private:
int Battery;
public:
NotebookComp(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 TableNotebook : public NotebookComp{
private:
char regstPenModel[50];
public:
TableNotebook(char * name, int initChag, char * pen) : NotebookComp(name, initChag){
strcpy(regstPenModel, pen);
}
void Write(char * penInfo){
if(GetBatteryInfo() < 1){
cout << "충전이 필요합니다."<<endl;
return;
}
if(strcmp(regstPenModel, penInfo) != 0){
cout << "등록된 펜이 아닙니다.";
return;
}
cout << "필기 내용을 처리합니다." << endl;
UseBattery();
}
};
int main(void){
NotebookComp nc("이수종", 5);
TableNotebook tn("정수영", 5, "ISE-241-242");
nc.MovingCal();
tn.Write("ISE-241-242");
return 0;
}
|
cs |
⭐️ISAInheritance.cpp 실행 결과
1
2
|
이동하면서 요청 내용을 계산합니다.
필기 내용을 처리합니다.
|
cs |
위 코드의 관계를 나타내면 다음과 같습니다.
🌼 HAS-A 관계
IS-A 관계 외에도 상속이 형성될만한 관계가 있습니다. 바로 '소유'의 관계입니다. 유도클래스는 기초 클래스가 지니고 있는 것을 모두 소유합니다. 다음과 같이 소유의 관계도 상속으로 표현이 가능합니다.
⭐️ HASInheritance.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#include <iostream>
#include <cstring>
using namespace std;
class Gun{
private:
int bullet;
public:
Gun(int bnum) : bullet(bnum){}
void Shot(){
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);
pman.Shot();
pman.PutHandcuff();
return 0;
}
|
cs |
⭐️ HASInheritance.cpp 실행결과
1
2
|
BBANG!
SNAP!
|
cs |
위 예제는 권총을 소유하고 있는 경찰을 표현했습니다. 그런데 이런 소유의 관계는 다른 방식으로도 표현이 가능합니다.
⭐️HASComposite.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#include <iostream>
#include <cstring>
using namespace std;
class Gun{
private:
int bullet;
public:
Gun(int bnum) : bullet(bnum){}
void Shot(){
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 Shot(){
if(pistol == NULL)
cout << "Hut BBANG!" << endl;
else
pistol -> Shot();
}
~Police(){
if(pistol!=NULL)
delete pistol;
}
};
int main(void){
Police pman1(5, 3);
pman1.Shot();
pman1.PutHandcuff();
Police pman2(0, 3);
pman2.Shot();
pman2.PutHandcuff();
return 0;
}
|
cs |
⭐️HASComposite.cpp
1
2
3
4
|
BBANG!
SNAP!
Hut BBANG!
SNAP!
|
cs |
HASComposite.cpp가 HASInheritance.cpp보다 더 좋은 코드일 가능성이 높은데, 왜냐하면 HASInheritance.cpp는 다음과 같은 요구사항을 만족시키지 못할 가능성이 높기 때문입니다.
💡 권총을 소유하지 않은 경찰을 표현해야 합니다.
💡 경찰이 권총과 수갑뿐만 아니라, 전기봉도 소유하기 시작했씁니다.
📜 출처
윤성우(2010). 윤성우 열혈 C++ 프로그래밍. 오렌지미디어.
'𝐏𝐑𝐎𝐆𝐑𝐀𝐌𝐌𝐈𝐍𝐆 > 𝐂++' 카테고리의 다른 글
C++ :: 멤버함수와 가상함수의 동작원리 (0) | 2020.08.28 |
---|---|
C++ :: 객체 포인터의 참고관계, 가상함수, 순수 가상함수, 가상 소멸자 (0) | 2020.08.27 |
C++ :: 상속(Inheritance) (0) | 2020.08.25 |
C++ :: const, friend 키워드 (0) | 2020.08.16 |
C++ :: 복사 생성자(Copy Constructor) (0) | 2020.08.16 |