virtual(가상 함수)

MwG·2024년 7월 26일

C++

목록 보기
1/21

함수 재정의

클래스에서 파생 클래스가 부모 클래스의 함수를 재정의 하여 사용 하는 것

class Base
{
public:
    void f()
    {
        cout << "Base" << endl;
    }
};

class Derived : public Base
{
public :
    void f()
    {
        cout << "Derived" << endl;
    }
};
 Derived d,*Pder;
 Pder = &d;

 Pder->f();
 Pder->Base::f();

이렇게 할 경우 원하는 대로 나옴

<업캐스팅>

 Base* Pba = Pder;
 Pba->f();

이렇게 할 경우 파생 클래스 함수가 아닌 부모 클래스 함수가 실행됨.

가상 함수(virtual fuction)

파생 클래스에서 부모 클래스에서 정의한 가상 함수를 재정의, 부모 클래스에서 정의한 가상함수를 무력화 하는 것..
즉 위 두 실행 방법에서 어떻게 실행 하든 상관없이 파생 클래스에서 재정의 된 함수로 실행됨..

virtual: 컴파일러에게 자신에 대한 호출 바인딩을 실행 시간까지 미루는 키워드

class Base
{
public:
   virtual void f() // 가상 함수 선언
   {
       cout << "Base" << endl;
   }
};
 Derived d,*Pder;
 Pder = &d;
 Pder->f();
 
 Base* Pba = Pder;
 Pba->f();

둘 다 파생 클래스의 함수로 실행된다.

class Base
{
public:
    virtual void f() // 가상 함수 선언
    {
        cout << "Base" << endl;
    }
};

class Derived : public Base
{
public :
    virtual void f() override //override될 가상 함수
    {
        cout << "Derived" << endl;
    }
};

이때 override 지시어를 함수 뒤에 적는게 좋다.

컴파일러가 override할 함수를 찾아 오류를 발견하는데 도움이 됨.

오버 라이딩 특징

  1. 가상 함수의 이름과 매개변수 타입, 개수 반환형이 일치 해야함.
  2. 오버 라이딩시, 파생 클래스에서 virtual 키워드는 생략 가능.
  3. 가상 함수의 접근 지정이 자유롭다.

추가) 오버 라이딩으로 무력화 된 부모 클래스의 함수를 실행 하는 법 => 범위 연산자(::) 사용

 Derived d;
 Base* Pba = &d;

 Pba->f();
 Pba->Base::f(); //부모 클래스 함수 호출 가능!

동적 바인딩

override는 동적 바인딩으로 실행된다.

동적 바인딩(Dynamic Binding) = 실행 시간 바인딩(run tume binding) = 늦은 바인딩(late binding)

=> 가상함수를 호출하는 코드를 컴파일 할 때, 바인딩을 실행 시간에 결정하도록 미룬다. 나중에 가상함수가 호출되면 실행 중 객체 내에 오버라이딩된 가상함수를 동적으로 찾아 호출한다.

final 지시어

<용도>
1. 클래스 상속 금지
2. 가상 함수 오버라이딩 무력화

class Base final //상속 금지
{
public:
    virtual void f() final// f()의 오버 라이딩 무력화 
    {
        cout << "Base" << endl;
    }
};

class Derived : public Base // 상속 불가능이므로 오류 발생
{
public :
    virtual void f() override //오버 라이딩이 불가능하므로 오류 발생
    {
        cout << "Derived" << endl;
    }
};

가상 소멸자

가상 소멸자 선언을 추천하는 이유
=> 부모 클래스에 대한 포인터로 파생 클래스의 객체를 delete하는 경우 정상적인 소멸을 하기 위해서이다.

가상 소멸자 선언을 안할 경우

class Base 
{
public:
    ~Base()
    {
        cout << "Base" << endl;
    }
};

class Derived : public Base 
{
public :
    ~Derived()
    {
        cout << "Derived" << endl;
    }
};

int main()
{
    Base* Pba = new Derived();
    delete Pba; //Base 소멸자만 실행됨.

    return 0;
}

가상 소멸자 선언을 할 경우

class Base 
{
public:
    virtual ~Base() // 가상 소멸자 선언
    {
        cout << "Base" << endl;
    }
};

class Derived : public Base 
{
public :
    virtual ~Derived()
    {
        cout << "Derived" << endl;
    }
};

int main()
{
    Base* Pba = new Derived();
    delete Pba; // Derived -> Base 소멸자 호출

    return 0;
}

순수 가상함수(Pure virtual fuction)

파생 클래스에서 재정의 해야할 함수를 알려주는 interface의 역할

class Base 
{
public:
    virtual void f() = 0; //순수 가상함수 선언
};

상속 받을 경우 무조건 재정의를 해야한다.

추상 클래스(Abstract class)

최소 하나의 순수 가상함수를 포함한 불완전힌 클래스 , 인스턴스를 생성할 수 없다.
=> 파생 클래스가 무조건 포함해야 하는 함수를 알려주는 인터페이스 용

class Base // 추상 클래스
{
public:
    
    void base() { f(); }

    virtual void f() = 0; //순수 가상함수 선언

};

class Derived : public Base //추상 클래스를 상속 받았으므로 추상 클래스
{
 
};
Base b; //추상클래스 인스턴스화 불가능
Base* Pb; // 포인터로는 선언 가능

Base* Pba = new Derived(); //파생클래스에서 부모 클래스에서 받은 순수 가상 함수를 
                            //정의하지 않을 경우 파생 클래스도 선언 불가능
delete Pba;

추상 클래스 구현

class Base // 추상 클래스
{
public:
    
    void base() { f(); }

    virtual void f() = 0; //순수 가상함수 선언

};

class Derived : public Base 
{
public :
    virtual void f() //순수 가상 함수 구현
    {
        cout << "Derived" << endl;
    }
};

int main()
{
    Base* Pba = new Derived(); //이제 Derived는 추상 클래스가 아니므로
                               //파생클래스 인스턴스(객체) 선언 가능
    delete Pba;
    return 0;
}

<출처>
dream_for
보리남편 김 주부
별준

0개의 댓글