C++
[C/C++ 강좌] 79강. 상속이 필요한 이유 (2)
코다람쥐
2022. 1. 19. 20:03
1. 상속이 필요한 두 번째 이유
#include <iostream>
#include <string>
using namespace std;
class Image {
public:
operator string() {
return "사진";
}
};
class Message {
public:
Message(int sendTime, string sendName)
: sendTime(sendTime), 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), 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), p_image(image) {}
Image* GetImage() const { return p_image; }
private:
Image* p_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 p_dogImage;
}
상속이 필요한 첫 번째 이유에서 나온 코드이다. main()함수에 있는 cout 관련된 내용들을 함수로 묶어서 메인함수 위에 다음과 같이 구현해보자.
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;
}
위 코드는 둘이 비슷하기 때문에 하나로 동적바인딩, 가상함수, 오버라이딩 등을 통해 하나로 묶어서 처리해 볼 수 있다.
#include <iostream>
#include <string>
using namespace std;
class Image {
public:
operator string() {
return "사진";
}
};
class Message {
public:
Message(int sendTime, string sendName)
: sendTime(sendTime), sendName(sendName) {}
int GetSendTime() const { return sendTime; }
string GetSendName() const { return sendName; }
virtual string GetContent() const { return ""; }
private:
int sendTime;
string sendName;
};
class TextMessage : public Message {
public:
TextMessage(int sendTime, string sendName, string text)
: Message(sendTime, sendName), text(text) {}
string GetText() const { return text; }
string GetContent() const{ return text; }
private:
string text;
};
class ImageMessage : public Message {
public:
ImageMessage(int sendTime, string sendName, Image* image)
: Message(sendTime, sendName), p_image(image) {}
Image* GetImage() const { return p_image; }
string GetContent() const { return (string)*p_image; }
private:
Image* p_image;
};
void printMessage(Message* m) {
cout << "보낸 시간 : " << m->GetSendTime() << endl;
cout << "보낸 사람 : " << m->GetSendName() << endl;
cout << " 내 용 : " << m->GetContent() << endl;
cout << endl;
}
int main() {
Image* p_dogImage = new Image();
TextMessage* hello = new TextMessage(10, "두들", "안녕");
ImageMessage* dog = new ImageMessage(20, "두들", p_dogImage);
printMessage(hello);
printMessage(dog);
delete p_dogImage;
}
1. virtual string GetContent() { return ""; }를 가상함수로 부모클래스에 정의하고
2. 자식클래스에서는 오버라이딩으로 처리하면
3. printMessage(Message *m)함수에서는 동적 바인딩을 통해 들어오는 자료형에 맞게 처리가 된다.
그래서 상속을 사용하면 printMessage()와 같은 함수를 일일히 오버로딩하지 않아도 되기 때문에 코드가 더 간결해진다.
이것이 상속을 사용하는 두 번째 이유이다.
참고로 참조변수를 통해서도 동적바인딩이 가능하다.
void printMessage(const Message& m) {
cout << "보낸 시간 : " << m.GetSendTime() << endl;
cout << "보낸 사람 : " << m.GetSendName() << endl;
cout << " 내 용 : " << m.GetContent() << endl;
cout << endl;
}
그리고 메인함수의 내용을 배열을 통해서도 간략화 할 수 있다.
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) { // 범위기반for문
printMessage(*m); // *m인 이유는 printMessage의 매개변수가 현재 참조변수로 정의됨
}
delete p_dogImage; // 메모리 해제
for(Message *s : messages) { // 메모리 해제
delete s;
}
}