[C++] 정사각형-직사각형 문제

2024. 6. 28. 18:17·Programming Language(Sub)/C++

정사각형-직사각형 문제

  • 앞에서 다이아몬드 문제에 의한 객체지향의 한계점을 살펴봤다면, 이번에는 정사각형-직사각형 문제로부터 객체지향의 한계점을 살펴보자
#include <iostream>
using namespace std;

class Rectangle {  // 직사각형
   public:
    Rectangle(double a, double b) : a(a), b(b) {}

   private:
    double a, b;
};

class Square {  // 정사각형
   public:
    Square(double a) : a(a) {}

   private:
    double a;
};
  1. 정사각형 is a 직사각형
  2. 네 변의 길이 모두
  • 따라서 정사각형과 직사각형을 상속관계로 구현해보자

  • 정사각형 is a 직사각형 이므로, 정사각형은 직사각형으로 부터 상속을 받아야 한다

    • 이 때 정사각형은 멤버 1개만 필요한데, 직사각형으로 부터 멤버 2개를 받아오게 된다
#include <iostream>
using namespace std;

class Rectangle {  // 직사각형
   public:
    Rectangle(double a, double b) : a(a), b(b) {}

   private:
    double a, b;
};

class Square : public Rectangle {  // 정사각형
   public:
    Square(double a) : Rectangle(a, a) {}
};

int main() {
    Square s(10);
}
  • 가로, 세로에 각각 a를 넣어주면 원하는 대로 동작하기는 한다

    • 정사각형이 직사각형으로부터 상속을 받으면서, sizeof(Square)가 2배가 되버리는 단점이 존재한다
#include <iostream>
using namespace std;

class Rectangle {  // 직사각형
   public:
    Rectangle(double a, double b) : a(a), b(b) {}
    void ResizeX(double k) { a *= k; }
    void ResizeY(double k) { b *= k; }

   private:
    double a, b;
};

class Square : public Rectangle {  // 정사각형
   public:
    Square(double a) : Rectangle(a, a) {}
};

int main() {
    Square s(10);
        s.ResizeX(2); // 이러면 s는 더 이상 정사각형이 아니게 된다(20, 10)
}
  • 만약 Rectangle에 Resize 함수가 존재한다고 하면

    • Square 인스턴스의 ResizeX()를 호출하면 s는 더 이상 정사각형이 아니게 된다
  • C++에서는 상속 받은 메서드를 삭제할 수 있다.

class Square : public Rectangle {  // 정사각형
   public:
    Square(double a) : Rectangle(a, a) {}
    void ResizeX(double k) = delete;
    void ResizeY(double k) = delete;
    void ResizeXY(double k) {
        Rectangle::ResizeX(k);
        Rectangle::ResizeY(k);
    }
};
  • 이렇게 하면 Square에서는 ResizeX와 ResizeY를 호출할 수 없을 것 같지만, 한 가지 함정이 더 있다.

  • 아래 예시에서는 Rectangle을 다형적 클래스로 선언한다.

#include <iostream>
using namespace std;

class Rectangle {  // 직사각형
   public:
    Rectangle(double a, double b) : a(a), b(b) {}
    virtual ~Rectangle() {}
    void ResizeX(double k) { a *= k; }
    void ResizeY(double k) { b *= k; }

   private:
    double a, b;
};

class Square : public Rectangle {  // 정사각형
   public:
    Square(double a) : Rectangle(a, a) {}
    void ResizeX(double k) = delete;
    void ResizeY(double k) = delete;
    void ResizeXY(double k) {
        Rectangle::ResizeX(k);
        Rectangle::ResizeY(k);
    }
};

int main() {
    Rectangle *r = new Square(10);
    r->ResizeX(2);
}
  • r->ResizeX(2); 를 막을 수 없는 문제가 발생한다

  • 또 다른 해결책 : immutable(불변) 클래스

    • ResizeX(), ResizeY()를 실행하면 Square 멤버 변수의 값 자체가 바뀌게 된다

    • 불변 클래스는 모든 멤버 변수가 const로 선언된 클래스이다.

#include <iostream>
using namespace std;

// 불변 클래스
class Rectangle {  // 직사각형
   public:
    Rectangle(double a, double b) : a(a), b(b) {}
    virtual ~Rectangle() {}
    Rectangle ResizeX(double k) const { return Rectangle(a * k, b); }
    Rectangle ResizeY(double k) const { return Rectangle(a, b * k); }
    double GetA() const { return a; }
    double GetB() const { return b; }

   private:
    const double a, b;
};

// 얘도 불편 클래스가 됨
class Square : public Rectangle {  // 정사각형
   public:
    Square(double a) : Rectangle(a, a) {}
};

int main() {
    Square s(10);
    Rectangle r = s.ResizeX(2);
    cout << s.GetA() << endl;
    cout << s.GetB() << endl;
    cout << r.GetA() << endl;
    cout << r.GetB() << endl;
}
  • 실행결과
10
10
20
10
  • s.ResizeX()는 s를 변경시키지 않는다

  • 불변 클래스를 사용하면 정사각형-직사각형 문제를 간단하게 해결할 수 있다.

  • 물론 아직 불필요한 멤버를 갖는 문제를 해결하지 못했다.

    • 만약 Square를 부모 클래스로 설계한다면?
#include <iostream>
using namespace std;

class Square {  // 정사각형
   public:
    Square(double a) : a(a) {}

   private:
    double a;
};

class Rectangle : public Square {  // 직사각형
   public:
    Rectangle(double a, double b) : Square(a), b(b) {}

   private:
    double b;
};

int main() {
    // 불가능 Rectangle *r = new Square(10);
}
  • 문제점

    • 멤버 변수의 관점에서 깔끔해보일 수 있으나, 상식에 어긋나고 코드를 보는 사람도 헷갈리게 된다

    • Rectangle을 통해서 Square를 가리키는 것도 불가능하다

  • 그래서 이 방법은 좋은 방법이 아님

  • 아직까지도 정사각형-직사각형 문제를 깔끔하게 해결할 수 있는 방법이 나타나지 않았다.

'Programming Language(Sub) > C++' 카테고리의 다른 글

[C++] 템플릿 특수화와 비타입 파라미터  (0) 2024.06.28
[C++] 함수 템플릿과 클래스 템플릿  (0) 2024.06.28
[C++] 다중 상속과 다이아몬드 문제  (0) 2024.06.28
[C++] 객체 지향 프로그래밍의 4대 원칙(원리)  (0) 2024.06.28
[C++] 상속에서의 형변환 - RTTI와 dynamic_cast  (0) 2024.06.28
'Programming Language(Sub)/C++' 카테고리의 다른 글
  • [C++] 템플릿 특수화와 비타입 파라미터
  • [C++] 함수 템플릿과 클래스 템플릿
  • [C++] 다중 상속과 다이아몬드 문제
  • [C++] 객체 지향 프로그래밍의 4대 원칙(원리)
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (457)
      • 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 (130)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (6)
        • 시스템 프로그래밍 (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++] 정사각형-직사각형 문제
상단으로

티스토리툴바