C++

[C/C++ 강좌] 79강. 상속이 필요한 이유 (2)

코다람쥐 2022. 1. 19. 20:03

https://www.youtube.com/watch?v=OuDGvbv7PwQ&list=RDCMUCmGcqqKdIKnH_-oHnkoyshg&start_radio=1&rv=OuDGvbv7PwQ&t=0

 

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;
    }
	
}