비가 상 메서드 재정의


84

Visual C ++ 2010에서이 시나리오를 가정 해 보겠습니다.

#include <iostream>
#include <conio.h>

using namespace std;

class Base
{
public:
    int b;
    void Display()
    {
        cout<<"Base: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Base: Virtual display."<<endl;
    };
};

class Derived : public Base
{
public:
    int d;
    void Display()
    {
        cout<<"Derived: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Derived: Virtual display."<<endl;
    };
};

int main()
{
    Base ba;
    Derived de;

    ba.Display();
    ba.vDisplay();
    de.Display();
    de.vDisplay();

    _getch();
    return 0;
};

이론적으로이 작은 응용 프로그램의 출력은 다음과 같아야합니다.

  • 기본 : 비가 상 디스플레이.
  • 베이스 : 가상 디스플레이.
  • 기본 : 비가 상 디스플레이.
  • 파생 : 가상 디스플레이.

Base 클래스의 Display 메서드는 가상 메서드가 아니므로 Derived 클래스는이를 재정의 할 수 없습니다. 권리?

문제는 응용 프로그램을 실행할 때 다음과 같이 인쇄된다는 것입니다.

  • 기본 : 비가 상 디스플레이.
  • 베이스 : 가상 디스플레이.
  • 파생 : 비가 상 디스플레이.
  • 파생 : 가상 디스플레이.

그래서 가상 메서드의 개념을 이해하지 못했거나 Visual C ++에서 이상한 일이 발생했습니다.

누군가가 설명을 도와 줄 수 있습니까?


당신은 절대적으로 Base : Non-virtual 디스플레이를 가질 것 입니다. 라인을 de.Base::Display().
v.oddou

답변:


128

네, 당신은 약간 오해하고 있습니다.

이 경우 파생 클래스에서 동일한 이름의 메서드는 부모 메서드를 숨 깁니다. 그렇지 않은 경우 기본 클래스 비가 상 메서드와 동일한 이름의 메서드를 만들려고하면 오류가 발생한다고 상상할 수 있습니다. 그것은 허용되며 문제가되지 않습니다. 그리고 당신이 한 것처럼 직접 메서드를 호출하면 괜찮다고 할 것입니다.

그러나 비가 상이기 때문에 다형성을 허용하는 C ++ 메서드 조회 메커니즘은 사용되지 않습니다. 따라서 예를 들어 파생 클래스의 인스턴스를 만들었지 만 기본 클래스에 대한 포인터를 통해 'Display'메서드를 호출하면 기본 메서드가 호출되는 반면 'vDisplay'의 경우 파생 메서드가 호출됩니다.

예를 들어 다음 줄을 추가해보십시오.

Base *b = &ba;
b->Display();
b->vDisplay();
b = &de;
b->Display();
b->vDisplay();

... 예상대로 출력을 관찰하십시오.

기본 : 비가 상 디스플레이.
베이스 : 가상 디스플레이.
기본 : 비가 상 디스플레이.
파생 : 가상 디스플레이.


@ sje397 안녕하세요, 답장을 보내 주셔서 감사합니다. 말했듯이 기본 클래스에 대한 포인터를 통해 메서드를 호출하는 예제를 작성할 수 있습니까? 감사합니다!
Leif Lazar

또한 내가 말했듯이 범위 확인 구문을 사용하여 파생 인스턴스에서 (가상이 아닌) 기본 메서드를 호출 할 수도 있습니다.
v.oddou

1
따라서 확실히하기 위해 기본 클래스에서 메서드를 정의하고 가상으로 선언하는지 여부에 관계없이 파생 클래스에서 재정의 할 수 있습니다. 유일한 차이점은 기본 포인터가 파생 클래스 개체를 가리키는 경우 해당 메서드를 호출하면 가상이 아닌 경우 기본 클래스의 메서드를 계산하고 가상 인 경우 파생 클래스의 메서드를 계산한다는 것입니다. 맞습니까? 다른 차이점이 있습니까?
SexyBeast

@Cupidvogel 네, 맞습니다. '가상'이라고 선언하면 C ++가 다형성을 지원하는 메커니즘을 사용하고 기본 클래스 포인터를 통해 호출 할 때 메서드의 더 파생 된 버전이 있는지 확인합니다. 다른 차이점은 생각할 수 없습니다.
sje397 2014

헤더 파일 만 변경하면 충분합니까? 아니면 "virtual"키워드로 소스를 컴파일해야합니까?
폴 크노프

14

예, 약간 오해했습니다.

순수 가상 기능 :

virtual void fun1()=0 -> 파생 클래스에서 재정의되어야합니다.

가상 기능 :

virtual void fun2() -> 재정의 가능

일반 기능 :

void fun3() -> 재정의하지 마십시오

런타임 다형성을 달성하려면 C ++에서 가상 함수를 재정의해야합니다.


5

정적 바인딩과 동적 바인딩의 맥락에서 보는 것이 더 나을 것이라고 생각합니다.

메서드가 가상이 아닌 경우 (Java와 달리 C ++에서는 기본적으로 이미 있음) 메서드는 런타임시 가리키는 실제 개체를 알 수없는 컴파일 타임에 호출자에게 바인딩됩니다. 따라서 변수 유형은 '베이스'가 중요한 모든 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.