오버라이딩(overriding) - 상위클래스의 함수를 하위클래스에서 재정의 해서 사용

오버로딩(overloading) - 같은이름의 함수를 매개변수 개수 또는 타입을 다르게하여 여러개의 함수를 정의

 

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

 

가상함수 - 부모 클래스에서 상속받을 클래스에서 재정의할 것으로 기대하고 정의해놓은 함수

⇒순수 가상함수 - 함수의 몸체를 정의 안함

⇒일반 가상함수 - 함수의 몸체를 정의함

virtual - 가상 함수를 가르키는 키워드 (부모 클래스 함수앞에 붙인다)

override - 부모 클래스의 함수를 재선언 및 재정의 (자식 클래스 함수 뒤에 붙인다, override된 함수를 호출할 경우 부모 클래스의 함수는 무시됨)

final - 가상 함수의 마지막을 가르키는 키워드 (더 이상 가상함수를 오버라이딩 하지 않음)

 

virtual 없이 override 하는 경우에는 기본 클래스 포인터로 override한 함수를 호출할 수 없다

 

#include <iostream>

using namespace std;

class A
{
public:
    void test(){
        cout << "a" << endl;
    }
};

class B : public A
{
public:
    void test() {
        cout << "b" << endl;
    }
};

class C : public B
{
public:
    void test(){
        cout << "c" << endl;
    }
};

int main(){

    A *a;
    B *b;
    C *c;

    a -> test();
    a = new B();
    a -> test();
    a = new C();
    a -> test();

    cout << endl;

    b -> test();
    b = new C();
    b -> test();

    cout << endl;

    c -> test();
}
 

 

B 클래스의  test함수만 가상함수로 만들었다

#include <iostream>

using namespace std;

class A
{
public:
    void test(){
        cout << "a" << endl;
    }
};

class B : public A
{
public:
    virtual void test() {
        cout << "b" << endl;
    }
};

class C : public B
{
public:
    void test() override{
        cout << "c" << endl;
    }
};

int main(){

    A *a;
    B *b;
    C *c;

    a -> test();
    a = new B();
    a -> test();
    a = new C();
    a -> test();

    cout << endl;
    b = new B(); // 가상함수는 동적할당이어서 메모리할당해주어야한다.

    b -> test();
    b = new C();
    b -> test();

    cout << endl;
    c = new C(); // 가상함수는 동적할당이어서 메모리할당해주어야한다.

    c -> test();
}
 
-----------------------------------------------------------------------------------
함수를 가상(virtual)으로 만드는 것은 컴파일러에게 "나는 함수가 어떻게 구현되는지 모른다. 프로그램에서 사용될 때까지 기다려라. 그리고 객체 인스턴스로부터 구현을 얻어라." 라고 말하는 것이다.

출처: https://flower0.tistory.com/234 [개발자 라면]

-----------------------------------------------------------------------------------

함수가 재정의 되어 C클래스의 test함수가 호출된다

 

-> virtual 키워드를 부모 클래스 앞에 붙여주면, 함수 호출시 자식 클래스의 함수가 호출됨

 

그런데 자식 클래스 함수에 override 를 없애주어도 똑같이 작동한다

그러면 override는 어쩔때 쓰는것일까

 

class A
{
public:
    void test(){
        cout << "a" << endl;
    }
};

class B : public A
{
public:
    virtual void test() {
        cout << "b" << endl;
    }
};

class C : public B
{
public:
    void test(int a){
        cout << "c" << endl;
    }
};

 

B클래스 test(void)와 C클래스 test(int)의 매개변수를 달리하여 함수를 정의하였다.

이것은 매개변수 타입을 달리하여 override 규칙을 무시한 것이다.

b = new B();

b -> test();
b = new C();
b -> test();
 

C클래스 에서 재정의한 b->test() 를 실행시켜보면은

C클래스에서 재정의한 int를 매개변수로 받는 test함수를 인식하지못하여 b가 출력되는것이다

 

이때 override를 사용하면

에러가 출력되는것을 확인할 수 있다.

 

 

매개변수가 서로다른 함수를 재정의할때 override를 사용하게끔 하여 가독성을높이고 재정의를 하는데 인자를 더 넣는다거나 반환형이 다르게 만든다거나 하는 실수를 컴파일러가 잡아낼수있는 것이다. (안전한 코딩이 가능)

 

c++ 에서 오버라이드 하기위해선

부모클래스의 함수앞에 virtual - (필수)

자식클래스의 함수뒤에 override - (선택) 하지만 안전한 코딩을 위한 사용이 권장됨

 

 

또한 순수가상함수는 자식클래스에서 '무조건' 재정의해야하는 함수

함수만 있고 본체가 없다는 의미로 함수 선언부 끝에 "=0"을 추가

class A
{
public:
    void test(){
        cout << "a" << endl;
    }
};

class B : public A
{
public:
    virtual void test() = 0; 
};

class C : public B
{
public:
    void test() {
        cout << "c" << endl;
    }
};

int main(){

    A *a;
    B *b;
    C *c;

    a -> test();
    a = new B();
    a -> test();
    a = new C();
    a -> test();

    cout << endl;
    b = new B();

    b -> test();
    b = new C();
    b -> test();
    
    c = new C();
    c -> test();
}
 

순수가상함수를 가지고있는 B클래스는 객체생성자체가 불가능하다.

 

이렇게 하나 이상의 순수 가상 함수를 포함하는 B클래스를 추상 클래스(abstract class)라고한다.

 

 

다음 예제는 비쥬얼스튜디오 공식 문서에있는 override 예제이다

class BaseClass
{
    virtual void funcA();
    virtual void funcB() const;
    virtual void funcC(int = 0);
    void funcD();
};

class DerivedClass: public BaseClass
{
    void funcA() override;  // 부모의 funcA()와 동일한 함수

    void funcB() override;  // 부모의 funcB()는 const 함수
                            // 자식의 funcB()와는 다른함수이다.
                            // 컴파일 에러
                            
    void funcB() const override; // 부모의 funcB() const와
                                 // 자식의 funcC() const가 동일하다
                            
    void funcC( double = 0.0 ) override; // 부모의 funcC()와 자식의 funcC()의 인자타입이 다르다.
                                         // 컴파일 에러

    void funcD() override;  // 부모의 funcD()함수가 가상함수가 아니기때문에 오버라이드 불가
                            // 컴파일 에러
};

 

'프로그래밍 > C++' 카테고리의 다른 글

this 포인터, 연산자 오버로딩  (0) 2022.04.15
멤버 초기화 리스트, 이니셜라이저  (0) 2022.04.13
const / constexpr / #define  (0) 2022.04.12
C++ 상속  (0) 2022.04.08
NULL / nullptr  (0) 2022.03.18

+ Recent posts