[C++] 상속이 필요한 이유(2)

2024. 6. 27. 22:10·Programming Language(Sub)/C++

상속이 필요한 이유(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
}
  • 위 코드를 오버라이딩을 통해서 효율적으로 개선해보자
  1. 부모 클래스 타입 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(Sub) > 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
'Programming Language(Sub)/C++' 카테고리의 다른 글
  • [C++] 생성/소멸자 실행 순서와 가상 소멸자
  • [C++] 순수 가상 함수와 추상 클래스
  • [C++] 가상 함수(Virtual Function)와 동적 바인딩(Dynamic Binding)
  • [C++] 오버라이딩(Overriding)과 정적 바인딩(Static Binding)
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (456)
      • Software Development (27)
        • Performance (0)
        • TroubleShooting (1)
        • Refactoring (0)
        • Test (8)
        • Code Style, Convetion (0)
        • DDD (0)
        • Software Engineering (18)
      • Java (71)
        • Basic (5)
        • Core (21)
        • Collection (7)
        • 멀티스레드&동시성 (13)
        • IO, Network (8)
        • Reflection, Annotation (3)
        • Modern Java(8~) (12)
        • JVM (2)
      • Spring (53)
        • Framework (12)
        • MVC (23)
        • Transaction (3)
        • AOP (11)
        • Boot (0)
        • AI (0)
      • DB Access (1)
        • Jdbc (1)
        • JdbcTemplate (0)
        • JPA (14)
        • Spring Data JPA (0)
        • QueryDSL (0)
      • Computer Science (129)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (5)
        • 시스템 프로그래밍 (23)
        • Algorithm (29)
      • HTTP (8)
      • Infra (1)
        • Docker (1)
      • 프로그래밍언어론 (15)
      • Programming Language(Sub) (77)
        • Kotlin (1)
        • Python (25)
        • C++ (51)
        • JavaScript (0)
      • FE (11)
        • HTML (1)
        • CSS (9)
        • React (0)
        • Application (1)
      • Unix_Linux (0)
        • Common (0)
      • PS (13)
        • BOJ (7)
        • Tip (3)
        • 프로그래머스 (0)
        • CodeForce (0)
      • Book Review (4)
        • Clean Code (4)
      • Math (3)
        • Linear Algebra (3)
      • AI (7)
        • DL (0)
        • ML (0)
        • DA (0)
        • Concepts (7)
      • 프리코스 (4)
      • Project Review (6)
      • LegacyPosts (11)
      • 모니터 (0)
      • Diary (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
lumana
[C++] 상속이 필요한 이유(2)
상단으로

티스토리툴바