프로그램/C,C++

[C++ 기본 4] 2. 추상클래스

naudhizb 2022. 5. 17. 19:53
반응형

객체지향에서 인스턴스화 시킬 수 없는 클래스를 추상클래스라 한다.
C++언어에서는 추상클래스를 함수의 값을 NULL(아마도 C언어에서 함수포인터를 NULL로 하는 것과 같은 듯 하다.)로 지정하는 것으로 추상 함수를 만들고, 추상함수를 가지고 있는 객체를 추상클래스로 지정한다.

C++에서는 보통 인터페이스를 구현하고자 할 때 추상클래스를 이용하여, 인터페이스를 구현한 객체가 해당 인터페이스를 필수로 구현하도록 컴파일러 단계에서 강제하는 방식을 주로 사용한다.

// 2_추상클래스    168 page
#include <iostream>
// 추상 클래스 : 순수 가상함수가 한개 이상 있는 클래스
// 특징 : 객체를 만들수 없다.
// 의도 : 특정 함수의 구현부를 제공하라고 지시 하는 문법.
class Shape
{
public:
    virtual void Draw() = 0; // 순수 가상함수(구현부가 없다.)
                             // pure virtual function
};
class Rect : public Shape   // Draw()의 구현부를 제공하지 않으면
{                            // 역시 추상 클래스이다.
};
int main()
{
    //Shape s; // error
    Rect  r;
}

예시를 들어보자.
사람이 카메라를 사용하고자 할 때 최초 Camera라는 객체를 이용하여 카메라를 찍고자 하였다. 그 이후에 HDCamera라는 객체를 추가로 만들어 카메라를 찍고자 하였을 때 아래의 예시에서는 다형성을 이용하여 HDCamera를 찍고자 하는 방법을 만들었다.

// 2_추상클래스2   171 page
#include <iostream>

class Camera
{
public:
    void take() { std::cout << "take picture" << std::endl; }
};
class HDCamera
{
public:
    void take() { std::cout << "take HD picture" << std::endl; }
};

class People
{
public:
    void useCamera(Camera* p) { p->take(); }
    void useCamera(HDCamera* p) { p->take(); }
};
int main()
{
    People p1;
    Camera c1;
    p1.useCamera(&c1);

    HDCamera hc;
    p1.useCamera(&hc);
}

이 경우 새로운 카메라가 만들어 질 때마다 카메라 객체를 생성하는 것 뿐만 아니라, 카메라를 사용하는 People 객체 까지도 변경해야하는 단점이 있다.

이를 개선한 예시는 아래와 같다.

#include <iostream>


// 카메라를 만들기 전에, 사람과 카메라 사이의 규칙을 설계하자.
// 규칙 : 모든 카메라는 아래 클래스로 부터 파생 되어야 한다. 라고 하지 말고

// 규칙 : "모든 카메라는 아래 인터페이스를 구현해야 한다." 라고 표현

#define interface struct

interface ICamera
{
    virtual void take()  = 0;
    virtual ~ICamera() {}
};


// 카메라는 없지만 규칙이 생겼다. 규칙대로 사용하면 된다.
class People
{
public:
    void useCamera(ICamera* p) { p->take(); }
    //void useCamera(ICamera& p) { p.take(); }
};

// 모든 카메라는 규칙대로 만들어야 한다.
class Camera : public ICamera
{
public:
    void take() { std::cout << "take picture" << std::endl; }
};
class HDCamera : public ICamera
{
public:
    void take() { std::cout << "take HD picture" << std::endl; }
};
int main()
{
    People p1;
    Camera c1;
    p1.useCamera(&c1);

    HDCamera hc;
    p1.useCamera(&hc);
}

위의 예시에서는 People이 카메라를 사용할 규칙인 ICamera를 먼저 추상 클래스로 구현하고, People은 ICamera를 이용하여 카메라를 사용한다.
그 다음 모든 Camera들은 ICamera를 상속받아 ICamera가 지정하는 추상 함수들을 가상함수로 구현하여 카메라가 추가될 때마다 Camera이외에 별도로 People의 코드가 변경되지 않도록 구현하여 유지보수성을 높일 수 있다.

반응형