상속이 필요한 이유(2)
- 상속이 필요한 이유(1) 코드
#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;
};
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;
}
- 출력 하는 부분(보낸 시간, 보낸 사람, 내용)이 공통적으로 존재하므로 printMessage라는 함수를 만들어서 처리해보자
void printMessage(TextMessage *m) {
cout << "보낸 시간 : " << m->GetSendTime() << endl;
cout << "보낸 사람 : " << m->GetSendName() << endl;
cout << "내용 : " << m->GetText() << endl;
cout << endl;
}
void printMessage(ImageMessage *m) {
cout << "보낸 시간 : " << m->GetSendTime() << endl;
cout << "보낸 사람 : " << m->GetSendName() << endl;
cout << "내용 : " << (string)*m->GetImage() << endl;
cout << endl;
}
int main() {
/* 생략 */
printMessage(hello); // TextMessage
printMessage(dog); // ImageMessage
}
- 위 코드를 오버라이딩을 통해서 효율적으로 개선해보자
- 부모 클래스 타입 Message의 포인터를 printMessage 함수의 파라미터 타입이 되도록 변경
void printMessage(Message *m) { // 상속과 오버라이딩을 통해 오버로딩을 하지 않아도 하나의 함수로 다 출력 가능.
cout << "보낸 시간 : " << m->GetSendTime() << endl;
cout << "보낸 사람 : " << m->GetSendName() << endl;
// cout << "내용 : " << m->GetText() << endl;
cout << "내용 : " << m->GetContent() << endl;
cout << endl;
}
GetText(), GetImage() 대신 Image, Text 등의 Content를 반환시킬 수 있는 GetContent() 함수를 부모 클래스(Message)에 가상 함수로 선언한 후 오버라이딩하자.
- 부모 클래스에서 반환할 Content가 존재하지는 않지만, 만약에 부모 클래스에서 GetContent 함수를 실행하면 빈 문자열을 반환하도록 구현
class Message {
/* 생략 */
virtual string GetContent() const { return ""; } // 추가된 코드
/* 생략 */
};
class TextMessage {
/* 생략 */
string GetText() const { return text; } // 기존에 존재하던 코드임
string GetContent() const { return text; } // 추가된 코드
/* 생략 */
};
class ImageMessage {
/* 생략 */
Image *GetImage() const { return p_image; } // 기존에 존재하던 코드임
string GetContent() const { return (string)*p_image; } // 추가된 코드
/* 생략 */
}
void printMessage(Message *m) { // 상속과 오버라이딩을 통해 오버로딩을 하지 않아도 하나의 함수로 다 출력 가능.
cout << "보낸 시간 : " << m->GetSendTime() << endl;
cout << "보낸 사람 : " << m->GetSendName() << endl;
cout << "내용 : " << m->GetContent() << endl; // GetContet()에서 동적바인딩이 일어남
cout << endl;
}
상속, 오버라이딩, 동적 바인딩을 통해서 여러 printMessage 함수를 하나의 함수로 만들었다.
아래와 같이 포인터 뿐만 아니라 레퍼런스를 통해서 오버라이딩 할 수도 있다.
void printMessage(const Message &m) { // 레퍼런스도 동적바인딩 가능, 만약 레퍼런스 없이 하면 객체가 복사되어, Message의 GetContent출력하게됨.
cout << "보낸 시간 : " << m.GetSendTime() << endl;
cout << "보낸 사람 : " << m.GetSendName() << endl;
cout << "내용 : " << m.GetContent() << endl; // 가상함수 동적바인딩.
cout << endl;
}
int main(void) {
Image *p_dogImage = new Image();
TextMessage *hello = new TextMessage(10, "두들", "안녕");
ImageMessage *dog = new ImageMessage(20, "두들", p_dogImage);
printMessage(*hello);
printMessage(*dog);
}
void printMessage(Message m)로 선언하게 되면, 매개변수로 전달되는 과정에서 Message로 바뀌어버리기 때문에, Message 클래스의 GetContent() 멤버 함수가 호출된다
메시지를 딱 2개만 보내는 상황은 거의 발생하지 않는다. 엄청 많은 메시지가 전송될텐데, 일일히 객체를 하나 씩 선언하고, 일일히 printMessage()를 호출할 수는 없다.
메시지를 담는 배열을 만들어보자
- 포인터 배열을 통해서 구현
int main() {
// 두들 : "안녕"
// 두들 : "강아지 사진"
Image *p_dogImage = new Image();
Message *messages[] = {
// 포인터배열을 통해 여러 메세지 가리키키
new TextMessage(10, "두들", "안녕"),
new TextMessage(11, "두들", "안녕"),
new TextMessage(12, "두들", "안녕"),
new ImageMessage(20, "두들", p_dogImage)};
for (Message *m : messages) {
printMessage(*m);
}
TextMessage *hello = new TextMessage(10, "두들", "안녕");
ImageMessage *dog = new ImageMessage(20, "두들", p_dogImage);
printMessage(*hello);
printMessage(*dog);
delete hello;
delete dog;
delete p_dogImage;
for (Message *m : messages) {
delete m;
}
}
'Programming Language > C++' 카테고리의 다른 글
[C++] 생성/소멸자 실행 순서와 가상 소멸자 (0) | 2024.06.27 |
---|---|
[C++] 순수 가상 함수와 추상 클래스 (0) | 2024.06.27 |
[C++] 가상 함수(Virtual Function)와 동적 바인딩(Dynamic Binding) (0) | 2024.06.27 |
[C++] 오버라이딩(Overriding)과 정적 바인딩(Static Binding) (0) | 2024.06.27 |
[C++] 상속이 필요한 이유(1) (0) | 2024.06.27 |