2016년 3월 7일 월요일

[c++] 순수 가상 함수, 추상클래스

우선 가상함수에 대해서 복습해보자. 가상 함수(Virtual Function)는 파생 클래스가 안전하게 재정의할 수 있는 함수이다. 만약 상속 관계가 아니라면 가상 함수를 선언할 필요가 없으므로 가상 함수는 상속 계층내에서만 의미가 있으며 파생 클래스에게 재정의 기회를 주기 위해 존재하는 것이라고 할 수 있다. 
 하지만 이 가상 함수를 반드시 재정의해야만 하는 것은 아니다. 기반 클래스의 동작을 그대로 쓰고 싶으면 단순히 상속만 받고 변경할 필요가 있을 때만 재정의하면 된다. Base 클래스가 가상 함수를 만드는 이유는 혹시라도 재정의하고 포인터로 호출할 때를 대비한 것이다. 가상 함수는 재정의해도 되는 함수이지 반드시 재정의해야 하는 함수는 아닌 것이다. 
 그럼 순수 가상 함수는 어떤가? 순수 가상 함수(Pure Virtual Function)는 파생 클래스에서 반드시 재정의해야 하는 함수이다. 순수 가상 함수는 일반적으로 함수의 동작을 정의하는 본체를 가지지 않으며 따라서 이 상태에서는 호출할 수 없다. 본체가 없다는 뜻으로 함수 선언부의 끝에 =0이라는 표기를 하는데 이는 함수만 있고 코드는 비어 있다는 뜻이다. 아래와 같이 클래스 단에서 선언한다.
  1. class Pure  
  2. {  
  3. public:  
  4.     virtual int vFunction() = 0;  
  5. };  
 또 이런 클래스(하나이상 가상함수를 지닌 클래스)를 추상 클래스(Abstract Class) 라고 일컫는다. 추상클래스는 완전한 클래스가 아니므로 객체화 될 수 없다

순수 가상 함수(Pure Virtual Function)
순수 가상함수는 구현이 없는 가상함수를 말합니다.
class Person
{
public:
    virtual void VirtualMethod() = 0;
};
구현 대신 가상함수에 NULL (0)값을 대입하면 해당 함수는 순수 가상함수가 됩니다.
이와 동시에
순수 가상함수를 포함하는 클래스는 추상 클래스(Abstract Class)로 지정됩니다.
추상 클래스 (Abstract Class)
추상 클래스가 되면 인스턴스를 만들 수 없게 됩니다.
다른 자식 클래스를 파생시켜서 모든 순수 멤버 가상함수를 오버라이드하면
해당 자식 클래스부터 인스턴스를 다시 생성할 수 있습니다.
즉,  추상 클래스는 ‘추상적인 형태’만 제안하고, 실제 구현은 자식 클래스로 미루기 위한 용도입니다.
#include <iostream>
class Person
{
public:
    void DoAction()
    {
        std::cout << "Good Morning!" << std::endl;
        Action();
        std::cout << "Sleep.." << std::endl;
    }
private:
    virtual void Action() = 0;
};

class Student : public Person
{
private:
    virtual void Action()
    {
        std::cout << "Study" << std::endl;
    }
};

class Employee : public Person
{
private:
    virtual void Action()
    {
        std::cout << "Work" << std::endl;
    }
};

int main(int argc, char** argv)
{
    Student student;
    Employee employee;

    student.DoAction();
    std::cout << std::endl;
    employee.DoAction();
}
Good Morning!
Study
Sleep..

Good Morning!
Work
Sleep..
위의 예제에서
Person은 Action이라는 순수 가상함수를 포함하는 추상클래스입니다.
멤버 함수인 DoAction은 “일어나서 Action을 하고 잠에 든다”로 동작을 확정했습니다.
즉, “어떠한 Action을 할 것인가”에 대한 문제는 자식으로 미뤄놓은 상태입니다.
이를 쉽게 비유하면, 큰 명제에 몇개의 괄호를 비워놓은 것이라고 할 수 있습니다.
학생은 “일어나서 [공부]를 하고 잠에 든다.”
직원은 “일어나서 [일]을 하고 잠에 든다.”
큰 흐름은 부모 혹은 클래스 외부에 미리 설계되어 있는대로 따라가지만,
세부적인 사항은 자식 클래스에 위임하는 것입니다

또한, 오직 추상적 설계만을 위해 디자인 된
모든 멤버 함수가 순수 가상함수인 클래스를 인터페이스(Interface)라고 부르기도 합니다.

댓글 없음:

댓글 쓰기

[Effective C++] 항목 30 : 인라인 함수는 미주알고주알 따져서 이해해 두자.

인라인 함수를 사용하면 컴파일러가 함수 본문에 대해 문맥별 최적화를 걸기가 용이해집니다. 인라인 함수의 아이디어는  함수 호출문을 그 함수의 본문으로 바꿔치기하자는 것  남발했다가는 코드의 크기가 커질 게 뻔하다. 인라인 함수로 부풀려진 ...