상속
부모클래스는 자기 자신의 멤버 변수만 접근이 가능하고
자식 클래스는 자기 자신의 멤버변수 뿐만 아니라 부모의 멤버변수에도 접근이 가능하다.
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
|
#include<iostream>
using namespace std;
class Base {
public:
void bFunc() {
cout << "Hello" << endl;
}
int bNum;
};
class Derived : public Base {
public:
void dFunc() {
cout << "Hello?" << endl;
}
int dNum;
};
int main() {
Base b;//부모 클래스
Derived d; //자식 클래스
b.bFunc();
b.bNum = 1;
//d에는 b의 모든 멤버와 d의 멤버도 접근가능
d.bFunc();
d.dFunc();
d.bNum = 2;
d.dNum = 1;
}
|
cs |
d객체는 bFunc,bNum에도 접근이 가능하다.
접근제어
상속을 할때 쓰이는 접근제어 지시자는 protected가 있다.
public ->외부 접근 허용 , 자식클래스에서 접근 허용
protected -> 외부 접근 비허용 ,자식클래스에서 접근 허용
private ->외부접근 비허용, 자식클래스에서 접근 비허용
class Derived : public Base 에서 public의 의미는 public으로 Base를 상속받아온다는 것이다.
만약 class Derived: protected Base 였다면 protected로 Base를 상속받아오는 것이여서
Base에서 public이였던 애도 protected로 상속받아오게 된다. (protected->protected ,private->원래대로 접근불가능)
오버라이딩
override는 '우선하다'라는 의미를 가지고 있다.
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
|
#include <iostream>
using namespace std;
//override:우선하다
class Base {
public:
int a = 10;
};
class Derived :public Base {
public:
int a = 20;
};
int main() {
Base b;
Derived d;
cout << b.a << endl;
cout << d.a << endl;
}
|
cs |
Derived라는 클래스를 잘 보면 Derived가 고유로 가지고 있는 a도 있지만 Base에서 상속받아온 a도 있다.
상속을 받아왔을 때 이름이 같다면 자기 고유의 것을 먼저 출력한다.그렇기에 d.a를 하면 Dervied의 고유의 값 a에 해당하는 20이 출력된다. 이것을 오버라이딩이 하고, "우선한다"는 것과 동치되는 말이기도 하다.
Derived에서 Base에 접근하고 싶다면
d.Base::a를 해주면 된다.
10이 출력(상속받아온 값) 되는 것을 알 수 있다.
상속관련 예제
메신저 프로그램을 만들건데, text와 이미지 변수로 private 필드를 구성한 프로그램을 만들어보자
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
#include <iostream>
#include <string>
using namespace std;
//메신저
//텍스트,이미지 주고받는 메신저 구현
class Image {
public:
operator string() {
//string으로 형변환
return "사진";
}
};
class Message {
public:
Message(int sendTime, string sendName) {
this->sendTime = sendTime;
this->sendName = sendName;
}
int GetSendTime()const {
return sendTime;
}
string GetSendName()const {
return sendName;
}
private:
int sendTime;
string sendName;
};
class TextMessage:public Message {
public:
TextMessage(int sendTime, string sendName, string text)
:Message(sendTime, sendName) {
//부모클래스의 생성자 먼저 실행
this->text = text;
}
string getText()const {
return text;
}
private:
string text;
};
class ImageMessage :public Message{
//이미지 자체를 동적할당할 수 있지만 이미지 안에 클래스에서 동적할당 된게 없기 때문에
//포인터 얕은 복사는 의미 없음.
public:
ImageMessage(int sendTime, string sendName,Image *image)
:Message(sendTime,sendName){
this->image = image;
}
Image* GetImage()const {
return image;
}
private:
int sendTime;
string sendName;
Image* image;//이미지는 용량이 크기 때문에 이미지에 대한 포인터값만 저장
};
int main() {
Image* p_dogImage = new Image(); //동적할당
TextMessage* hello = new TextMessage(10, "두들", "안녕");
ImageMessage* dog = new ImageMessage(20,"두들", p_dogImage);
cout << "보낸시간: " << hello->GetSendTime() << endl;
cout << "보낸 사람: " << hello->GetSendName() << endl;
cout << "내용:" << hello->getText() << endl;
cout << endl;
cout << "보낸시간: " << dog->GetSendTime() << endl;
cout << "보낸 사람: " << dog->GetSendName() << endl;
cout << "내용:" << (string)*dog->GetImage() << endl;
delete hello;
delete dog;
delete p_dogImage;
}
|
cs |
이 코드에서 중요한건 세가지이다.
1. 상속을 이용해 Message 부모 클래스를 만들고 -> TextMessage, ImageMessage 로 자식클래스를 만들었다.
자식클래스인 TextMessage를 잘 보면 생성자 위임 처럼 보이는 Message(sendTime,sendName)이 있다. 얘를 상속받아 온거기 때문에 부모 클래스의 생성자가 먼저 실행되고 -> 자식 클래스의 생성자가 실행된다.
2. 부모클래스에서는 protected 보단 생성자를 이용해주자!
부모클래스와 자식클래스에는 공통적으로 sendTume과 sendName이 들어간다. 이럴떈 부모클래스의 protectd필드에
이 두변수를 선언해주기 보다는 그냥 부모 클래스 생성자에 sendTime과 sendName이 매개변수로 들어가는 생성자를
만들어줘서 자식클래스가 부모클래스의 생성자를 상속받을 수 있게 한다.
내 느낌에는 원래 부모 클래스의 private 필드에 있는 sendTIme이나 sendName이 변질되면 안되는데
protected로 선언되면 변질이 될 수 있기에 그냥 얘는 private로 유지시켜주고 생성자만 상속시켜주는 것 같다.
그리고 this->sendTime안하고 sendTime하면 매개변수랑 똑같이 인식하기 때문에 당연히 에러가 뜬다.
this포인터를 이용해 private 필드에 있는 나 자신의 sendTime에 접근해주는 거다.
[TMI정보들]
1) (string)*dog->GetImage() 의 의미는 무엇일까?
main함수에 독특한 코드가 있다. 이건 dog->GetImage를 하면 dog가 포인터이기 때문에 (동적할당 하느라)
주소값이 반환된다. 그래서 * 해주면서 얘가 반환된 값을 가리키게 하고 (string)은 맨 위에 Image 클래스에
string 형변환 메서드를 통해 string 형변환이 되게 해주는 것이다.
2) ImageMessage에서 얕은복사 해줘도 될까?
this->image=image;를 하면 얕은 복사가 될것이다.
이미지 자체를 동적할당 할수 있기는 하다. 그러나 이미지 클래스 자체를 보자.
여긴 동적할당 된 메모리가 없다. 그래서 포인터 얕은 복사 해줘도 아무 문제 없다.
3) 생성자에서 this포인터 쓰는 이유?
this->sendTime을 해주면서 멤버변수의 sendTime에 접근한다.(멤버변수와 매개변수명이 같아서 둘을 구분하기 위해 this쓰는것!)
'C++ > 기초(두들낙서)' 카테고리의 다른 글
[C++기초] 동적할당과 객체복사 연습문제 (0) | 2022.01.17 |
---|---|
[C++기초] 정적 바인딩/가상함수와 동적바인딩 (0) | 2022.01.17 |
[C++기초] 묵시적 형변환 (0) | 2022.01.16 |
[C++기초] 깊은 복사, 얕은 복사 - 이동시맨틱,이동생성자,이동 대입연산자 (0) | 2022.01.16 |
[C++기초] 깊은복사, 얕은 복사 - 대입연산자 (0) | 2022.01.16 |
댓글