2013-10-01 2 views
1

다음은 가상 메서드를 재정의 할 때 표시되는 코드입니다. 출력 : B B A A B 이 맞습니까? bar 메서드를 재정의 할 수 없다고 생각했는데 ...?비 가상 메서드 재정의?

#include <iostream> 
using namespace std; 


class A 
{ 
public: 
    virtual void foo(){cout<<"A"<<endl;} 
      void bar(){cout<<"A"<<endl;} 
}; 

class B : public A 
{ 
public: 
    void foo(){cout<<"B"<<endl;} 
    void bar(){cout<<"B"<<endl;} 
}; 

int main() 
{ 
    B b; 
    A * pA = new A; 
    A * pA2 = &b; 
    b.foo(); b.bar(); 
    pA->foo(); pA->bar(); 
    pA2->foo(); pA2->bar(); 

}  
+1

은'bar' 방법은 가상 있다면, 그것은'B B A A B B'를 인쇄 할이 ... 연평균 삭제하는 것을 잊지 마세요. 너의 요점이 뭐야? – rici

+0

@Rachel : 맞습니다. 'bar'를 재정의 할 수 없습니다. 그리고 그렇지 않습니다. 'bar'가 오버라이드 된 경우 출력은'B B A A B B'가됩니다. 당신은'B B A A B A'를 얻었습니다. 그것은 막대가 오버라이드되지 않기 때문에 매우 구체적입니다. 그래서, 당신의 질문은 무엇입니까? – AnT

답변

1

b.foo()

b.bar()A::bar() 숨겨 B를 제공 B 준다. 무시하지 않고 이름 숨기기입니다.

pA->foo()는 가상 함수이므로

pA2->foo()

B를 제공 pA->bar()A를 제공 A을 준다.

pA2->bar()은 가상 기능이 아니기 때문에 A이됩니다. 정적으로 연결되어 있으며 A::bar()을 호출합니다.

1

타입 B의 객체에 대해 foo() 및 bar()를 호출하기 때문에 첫 번째 두 출력은 모두 B 여야합니다. 포인터를 사용하지 않으므로 컴파일러는이 객체가 B 유형의 객체라는 것을 알고 있으므로 메서드를 호출하기 위해 vtable을 참조 할 필요가 없으므로 bar()가 가상이 아니더라도 컴파일러는 B 구현을 사용하는 것을 알고 있습니다.

타입 A의 객체에 대한 포인터에서 foo() 및 bar()를 호출하기 때문에 다음 두 출력이 모두 A가되어야합니다.이 경우 foo()는 가상이고 vtable은 메서드의 구현 bar()는 가상이 아니므로 컴파일러는 A 구현을 사용하기로 결정합니다.

마지막 두 출력은 B 유형의 객체에 대한 포인터에 대해 foo() 및 bar()를 호출하기 때문에 B와 A가되어야합니다.이 경우 foo()는 가상이고 vtable은 메소드의 B 구현. 바() 가상 아니기 때문에 컴파일러는

2

내가 잘못 아무것도 표시되지 않습니다 당신이 A 형의 객체에 대한 포인터를 사용하고 이후는 A 구현을 사용하기로 결정 :

B b; 
b.foo(); b.bar(); 

당신을 B, 컴파일 유형이 B, 런타임 유형이 B 인 인스턴스를 선언하고 초기화합니다. 다형성은 필요하지 않습니다 (포인터가 관련되어 있지 않으므로 달성 할 수 없습니다).

A * pA = new A; 
pA->foo(); pA->bar(); 

당신은 A에 대한 포인터를 선언하고 A의 인스턴스를 초기화합니다. 다형성은이 경우에 필요하지 않더라도 작동하므로 A에서 foo()bar()이 호출됩니다.

A * pA2 = &b; 
pA2->foo(); pA2->bar(); 

당신은 A에 대한 포인터를 선언하고 B에 대한 참조를 초기화합니다. 컴파일 시간 유형은 A*이고 런타임 유형은 B*입니다.가상 함수를 통한 다형성이 적용되므로 가상 메서드는 B::foo()이고 가상이 아닌 것은 A::bar()

0

올바른지, pA2-> bar() 호출은 무시되지 않습니다. B 객체이지만 A로 캐스팅하고 A 클래스의 A 멤버 함수를 컴파일러에서 호출합니다.

foo()는 가상 클래스이므로 클래스의 내부에는 foo()의 버전이 캐스트 된 위치에 관계없이 클래스에 대해 올바른 포인터가 포함됩니다.

이 포함은 가상 함수 테이블에 대한 포인터라고합니다. 클래스가 가상 멤버에 올 자마자 정적 함수 테이블이 만들어지고 (다른 가상 함수도 포함될 것입니다), 추가로 상수 숨겨진 멤버 포인터가이 테이블을 가리 킵니다. 객체를 캐스팅 할 때 함수 테이블은 변경되지 않고 모든 가상 함수는 원래 유형에 '연결된'상태로 유지됩니다.

PS는 현재 메모리 누수 :