상속이 필요한 이유(1)
상속이 필요한 이유에 대해서 알아보자
example) 메신저 프로그램
텍스트, 이미지 등의 포맷을 갖는 데이터를 전송한다
상속을 사용하지 않고 코드를 작성해보자
// 상속을 사용하지 않은 코드
#include <iostream>
#include <string>
using namespace std;
class Image {
public:
operator string() {
return "사진";
}
};
class TextMessage {
public:
TextMessage(int sendTime, string sendName, string text) {
this->sendTime = sendTime; // this->sendTime을 안쓰고 sendTime을 쓰면 매개변수 값을 매개변수에 넣는 꼴.
this->sendName = sendName;
this->text = text;
}
int GetSendTime() const { return sendTime; }
string GetSendName() const { return sendName; }
string GetText() const { return text; }
private:
int sendTime;
string sendName;
string text;
};
class ImageMessage {
public:
ImageMessage(int sendTime, string sendName, Image *image) {
this->sendTime = sendTime;
this->sendName = sendName;
this->image = image;
}
int GetSendTime() const { return sendTime; }
string GetSendName() const { return sendName; }
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;
cout << endl;
delete hello;
delete dog;
delete p_dogImage;
}
참고) 실제로 Image를 출력하는 기능을 구현하기에는 복잡하므로 Image 타입을 string으로 형변환하여 사용하도록 구현하였다.
ImageMessage 클래스와 TextMessage 클래스를 따로 선언하였다
SendName, SendTime을 공통적으로 가지고 있음
이미지 메시지 클래스와 텍스트 메시지 클래스의 공통 부모를 만들어보자.
- 부모에 두 공통멤버를 넣고, 부모에서 이미지 메시지와 텍스트 메시지에 상속해주는 방식으로 구현할 수 있다.
상속을 이용해서 사용한 코드
// 상속을 사용한 코드
#include <iostream>
#include <string>
using namespace std;
class Message {
public:
Message(int sendTime, string sendName) {
this->sendTime = sendTime; // this->sendTime을 안쓰고 sendTime을 쓰면 매개변수 값을 매개변수에 넣는 꼴.
this->sendName = sendName;
}
int GetSendTime() const { return sendTime; }
string GetSendName() const { return sendName; }
private:
int sendTime;
string sendName;
};
class Image {
public:
operator string() {
return "사진";
}
};
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:
Image *image;
};
공통 멤버를 부모 클래스로 뽑아내고 멤버 공개 level을 protected로 바꾸는 것 보단, private을 유지하면서 부모 클래스의 생성자나 멤버 함수를 통해 접근하는 방식을 사용하자
- 정보 은닉(Encapsulation), 클래스 불변성 유지, 캡슐화, 유지보수성에서 훨씬 유리하다
자식 클래스의 생성자가 호출될 때, 컴파일러는 가장 먼저 부모 클래스의 생성자를 호출하려고 시도하게 된다. 이 때 생성자 오버로딩을 통해 생성자가 여러 개 존재하는 경우가 있을 수 있으므로, 모호성이 발생하지 않도록 자식 클래스의 생성자에서 부모 클래스의 어떤 생성자를 호출할 것인지를 명시해줘야 한다
TextMessage(int sendTime, string sendName, string text) : Message(sendTime, sendName)
ImageMessage(int sendTime, string sendName, Image *image) : Message(sendTime, sendName)
이전에 다뤘던 생성자 위임의 문법을 사용하면 된다
이렇게 클래스 구조를 수정했지만, 메인함수에서 아무것도 수정하지 않아도 동일한 결과를 얻는다
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;
cout << endl;
delete hello;
delete dog;
delete p_dogImage;
}
- 여기서 알 수 있는 상속의 장점 : 자식 클래스를 일일히 다 수정하지 않아도, 공통적인 내용을 뽑아낸 부모 클래스를 수정하면 모든 자식 클래스가 바뀌게 된다.
'Programming Language > C++' 카테고리의 다른 글
[C++] 가상 함수(Virtual Function)와 동적 바인딩(Dynamic Binding) (0) | 2024.06.27 |
---|---|
[C++] 오버라이딩(Overriding)과 정적 바인딩(Static Binding) (0) | 2024.06.27 |
[C++] 상속(Inheritance)과 접근제어(Access Control) (0) | 2024.06.27 |
[C++] Implicit Conversion(묵시적 형변환) (0) | 2024.06.27 |
[C++] 이동 시맨틱(Move Semantics): 이동 생성자, 이동 대입 연산자 (0) | 2024.06.27 |