2013-04-26 8 views
0

모든 :상속 클래스 구조는 어떻게 생겼습니까?

#include <iostream> 
using namespace std; 
class Base{ 
public: 
virtual void f(float x){cout<<"Base::f(float)"<<x<<endl;} 
     void g(float x){cout<<"Base::g(float)"<<x<<endl;} 
     void h(float x){cout<<"Base::h(float)"<<x<<endl;} 
}; 

class Derived:public Base{ 
public: 
virtual void f(float x){cout<<"Derived::f(float)"<<x<<endl;} 
     void g(int x){cout<<"Derived::g(int)"<<x<<endl;} 
     void h(float x){cout<<"Derived::h(float)"<<x<<endl;} 
}; 
int main(void){ 
    Derived d; 
    Base *pb=&d; 
    Derived *pd=&d; 

    //Good:behavior depends solely on type of the object 
    pb->f(3.14f);  //Derived::f(float)3.14 
    pd->f(3.14f);  //Derived::f(float)3.14 

    //Bad:behavior depends on type of the pointer 
    pb->g(3.14f);  //Base::g(float)3.14 
    pd->g(3.14f);  //Derived::g(int)3(surprise!) 

    //Bad:behavior depends on type of the pointer 
    pb->h(3.14f);  //Base::h(float)3.14(surprise!) 
    pd->h(3.14f);  //Derived::h(float)3.14 


    return 0; 
} 

공부 가상 함수 후, 나는 내가 어떻게 형체 작업 아이디어를 가지고 생각하지만, 여전히 몇 가지가 있습니다 : 나는 C++에서 다형성을 연구 할 때

, 나는 여기에 작은 예를 찾을 수 이 코드의 질문, 나는이 코드가 어떻게 작동하는지 설명하는 누군가를 귀찮게하지 않으려 고합니다. 파생 된 클래스 내에서 세부 정보를 표시 할 수있는 사람이 필요합니다 (너무 자세하게 설명 할 필요가 없으며, 메서드 포인터 Vtable과 그 구조는 가상 상속되지 않습니다.

pb-> h (3.14f); //Base::h(float)3.14 (깜짝!) 몇 가지 vtable이 있어야합니다. 맞습니까?

감사합니다.

+0

자네 말이 맞아. 함수는'virtual'이어야하며, 이는 각 클래스 유형에 대한 vtable을 제공합니다. –

+0

죄송합니다 드류, 내 가난한 영어입니다! 이 코드는 작동합니다. 파생 클래스 구조에 대한 내부 정보를 알고 싶습니다. – Kuan

답변

2

코드에는 하나의 다형성 (virtual) 멤버 함수 서명 (f(float)) 만 있습니다. 다른 세 함수, g(float), g(int)h(float)은 가상이 아닙니다. "놀람!"주석은 g()h()에 대한 호출 이후이므로이 함수가 다형성이 아니거나 실제로 비 다형 함수의 동작에 놀라는지 궁금합니다. 당신이 g()h() 다형성하지 놀랐 경우

virtual 다형성 함수 앞에 배치되는 것을 알고 있습니다. 함수가 virtual으로 선언되지 않은 경우에는 기본 클래스의 가상 함수와 동일한 서명이있는 경우에만 다형성을 갖습니다 (이는 virtualDerived에 중복됨을 의미하지만 실제로는 virtual과 같은 중복 사용을 느낍니다. 좋은 스타일). virtualf(float) 앞에 표시되기 때문에 f(float) 만 다형성을 갖습니다.

h()은 다형성이 아니므로 h()을 기본 포인터를 통해 h()이라고 부르는 것은 놀라운 일이 아닙니다.

g()에 대해서는 using 선언을 통해 다시 가져 오지 않는 한 파생 클래스의 이름이 기본 클래스의 해당 이름을 숨 깁니다. 따라서 pd->g(3.14f)Base::g(float)이 더 적합한 경우에도 Derived::g(int)을 호출하는 이유입니다. Base::g이 보이지 않습니다. using Base::g;을 Derived 클래스에 넣으면 float 버전의 g()이 호출됩니다. (g(int)g(float)는 다른 기능 서명 때문에, virtual 여기 g()에 대한 차이도하지 않습니다 것을 참고 - 하나가 다른를 오버라이드 (override) 할 방법은 없습니다.)

HTH

+0

감사합니다. 아담, 포인터가 함수에 따라 위치를 찾는 방법과 같이 물리적 구조 측면에서 설명 할 수 있는지 궁금합니다. – Kuan

+0

@Kuan : 다형 함수의 구현은 표준의 일부가 아니므로 컴파일러에서 컴파일러에 이르기까지 구현 정보가 잘못되었을 수 있습니다. 그러나 식별자 (예 : 식별자)는 매우 일반적입니다.파생 형식을 식별하거나 가상 호출에 대한 코드/데이터 오프셋 테이블을 찾는 데 사용되는 다형 클래스의 인스턴스 시작 부분에 배치 할 포인터 (예 : 포인터) 때로는 각 인스턴스에 하나 이상의 이러한 태그가 있습니다 (종종 다중 상속 포함). 이러한 테이블의 세부 사항은 플랫폼에 따라 다릅니다. 대신에 필요한 행동을 배우는 것이 낫습니다. –

+0

감사합니다 아담,하지만 당신이 저에게 가상 상속/비 가상 상속, 오버로딩, 오버라이드 및 숨김과 관련된 규칙을 기억하거나 카테고리 화하는 방법에 대한 팁을 저에게 줄 수 있는지 궁금합니다. 아니면 그 중 어떤 규칙을 기억하는 것이 가장 중요하다고 생각합니까? – Kuan

관련 문제