2013-03-03 2 views
1

오버로드 및 오버라이드의 기본 사항을 이해하지만 뭔가 혼란 스럽습니다. I는 간단한 예를 사용하여 설명하려고한다 :어떻게 오버로딩과 오버라이드가 함께 작동합니까?

  • 클래스 B가
  • 클래스 D는 X와 X보다 우선
  • 클래스 D가 클래스 B를 계승 함수 X (B & B)을 가진다 (B & B) 또한 X로 과부하 (D & d).

    void test(D& d1, B& b1, D& d2, B& b2){ 
        d1.X(d2); 
        d1.X(b2); 
        b1.X(d2); 
        b1.X(b2); 
    } 
    
    int main(){ 
        D d1, d2, d3, d4; 
        test(d1, d2, d3, d4); 
    } 
    

    내가 test()의 세 번째와 네 개의 라인이 일반적인 메커니즘이있는 어떤 전화를 할 X()의 구현을 결정 얼마나 매우 확실하지 오전 :

나는 다음 코드를 사고.

+2

다형성은 포인터와 참조에서만 발생합니다. 값을 전달하면 'D'가 'B'로 분할됩니다. 또한 그것을 고치더라도,'B :: '를 통해'X'를 호출 할 때 과부하'D :: X (D)'가 보이지 않습니다. –

+0

@SethCarnegie 참조를 포함하도록 게시물을 수정했습니다. 분명히 b1.X (b2)는 DX (B & b)를 호출 할 것입니다 ..... 이것은 내가 이해하지 못하는 것입니다 ... – user997112

+0

'B'는'X (D)'함수가없고'D' 만 않습니다. 또한 함수의 인수 유형 (가상 또는 정적 중 하나)은 정적이 아닌 동적으로 가져옵니다. –

답변

1

과부하 선택 (X(B&)X(D&))과 두 가지 단계가 있습니다. 일단 완료되면 선택한 기능의 올바른 구현을 찾습니다. 전자는 컴파일 시간에 발생하고 정적 유형의 객체 인수에 따라, 후자는 실행시 발생과 개체의 동적 유형에 따라 (가 가에 의존하지 않습니다 인수의 동적 유형).자신의 정적 형식 있도록D&이며, d1d2D&, 그리고 자신의 정적 유형 B& 그래서 b1b2B&로 선언 다음과 같이

네 개의 개체가 선언됩니다. 정적 유형은 코드에서 선언 한 것입니다. 네 개의 참조가 실제로 당신이 main()D -objects으로 만든 개체를 참조하기 때문에 네 가지에 대한

그러나 동적 유형D입니다.

따라서, 첫 번째 단계는, 과부하 선택 : 정적 유형 B&이고 B 대한 클래스 정의는이 하나 개의 기능을 갖기 때문에 b1.X(b2)b1.X(d2) 인 경우, 단지 하나의 가능한 과부하 X(B&)이있다. 그러나 d1.X(b2)d1.X(d2)의 경우 정적 유형이 D&이므로 오버로드 선택은 D의 클래스 정의를 기반으로합니다. 따라서 두 가지 오버로드가 고려됩니다 (X(B&)X(D&)). 인수 b2 인 경우, 이전의 과부하가 선택되고, 인수 d2 때, 후자 과부하 정적 (= 선언) 개체와 인수 유형에 기반 – 모두 선택된다.

두 번째 단계는 선택한 과부하의 올바른 구현을 선택하는 것입니다. 이것은 런타임에 발생하며 객체의 동적 유형 (인수가 아님)에 따라 다릅니다. 따라서 b1.X(b2)의 경우 동적 유형 b1D이므로 D::X(B&)을 호출하게됩니다. b1.X(d2)과 동일 : 이전 단계에서 선택한 과부하는 X(B&)이지만 선택한 구현은 D::X(B&)입니다. (D::X(D&)은 다른 오버로드가 될 것이고 이미 오버로드가 정적 유형을 기반으로 선택 되었기 때문에이 시점에서 후보가 아닙니다. 오브젝트의 동적 형태는 정지형 같기 때문에 d1.X(b2)d1.X(d2)의 경우, 선택된 기능은, 첫 번째 단계, D::X(B&)D::X(D&)과 동일하다.

+0

우수 답변 - 당신이 정말로 이것을 잘 설명했습니다! – user997112

+0

따라서, 호출하는 객체 (D)의 정적 유형과 동적 유형이 일치하기 때문에 첫 번째 두 개의 할당에 대해 두 번째 단계를 살펴 보는 것은 번거롭지 않습니다. 즉, 첫 번째 단계에서는 정적 유형 오버로드를 호출하고 두 번째 단계에서는 상속 계층의 클래스에서이 오버로드 된 함수를 호출 할 것인지 결정합니다 (동적 유형이 정적 유형과 일치하지 않는 경우). – user997112

+0

예, 맞습니다. 실제로는 두 번째 단계가 수행되지만 동적 유형은 정적 유형과 동일하므로 아무 것도 변경하지 않습니다. – jogojapan

2

가상 함수 XB(B::X)에 선언하고 파생 클래스 D(D::X)X을 재정의합니다. B::XD::X의 매개 변수 목록이 B::XD::X가 다른 고려, 다른 경우 (가상 키워드로 선언하지 않는 한), D::XB::X을 무시하지 않으며, D::X 가상 없습니다. 대신 D::XB::X을 숨 깁니다.

#include <iostream> 
using namespace std; 

struct B { 
    virtual void X() { cout << "Class B" << endl; } 
}; 

struct D: B { 
    void X(int) { cout << "Class D" << endl; } 
}; 

int main() { 
    D d; 
    B* pb = &d; 
// d.X(); 
    pb->X(); 
} 

심지어 d.X()를 호출 할 수 없습니다, 그것은 D::X(int)으로 숨겨져 있습니다. 그러나 pb->X()은 문제가 없습니다. 따라서 귀하의 경우

:

struct B { 
    virtual void X(B& b) { cout << "Class B" << endl; } 
}; 

struct D: B { 
    void X(B& b) { cout << "Class D" << endl; } 
    void X(D& d) { cout << "Class D" << endl; } 
}; 

D::XB::X을 숨 깁니다. 그래서 d1.X(d2)d1.X(b2)test()과 아무 관계가 없습니다. B::X. b1.X(d2)b1.X(b2)test()입니다. 전화 번호는 D::X입니다. B::X은 D에서 보이지 않지만 D::X(B&)을 가상 키워드와 함께 선언하는지 여부와 관계없이 D::X(B&)은 가상입니다. 컴파일러는 그것이 가상 함수라는 것을 알고 있으므로 D::X(B&)이 호출됩니다.

EDIT : B1.X (b2)에 대한 설명이 더 많습니다. B :: X는 가상 함수이고 D :: X는이를 무시하므로 확실히 동적 바인딩으로 D :: X를 호출합니다. 그리고 오버로딩은 컴파일 시간에 결정되므로 D :: X (D &)를 호출하지 않습니다.

+0

마지막 '왜 안되니?'는 질문처럼 보입니까? @jogojapan – StarPinkER

+0

그는 내게 질문을 던졌을 때 "내가 무슨 뜻인지 알 겠어?"라고 물었습니다. – user997112

+2

좋아, 내 영어 문제라고 생각해. – StarPinkER

관련 문제