2017-03-12 2 views
1

기본 클래스 포인터를 생성하고 새 파생 클래스를 할당했습니다.파생 클래스에 할당 된 기본 클래스 포인터

class Base 
{ 
public: 
    virtual void f(int); 
    virtual void f(double); 
    virtual void g(int i = 10); 
}; 

void Base::f(int) 
{ 
    cout << "Base::f(int)" << endl; 
} 

void Base::f(double) 
{ 
    cout << "Base::f(double)" << endl; 
} 

void Base::g(int i) 
{ 
    cout << i << endl; 
} 

class Derived: public Base 
{ 
public: 
    void f(complex<double>); 
    void g(int i = 20); 
}; 

void Derived::f(complex<double>) 
{ 
    cout << "Derived::f(complex)" << endl; 
} 

void Derived::g(int i) 
{ 
    cout << "Derived::g() " << i << endl; 
} 

void main() 
{ 
    Base b; 
    Derived d; 
    Base* pb = new Derived; 
    b.f(1.0); 
    d.f(1.0); 
    pb->f(1.0); 
    b->g(); 
    d->g(); 
    pb->g(); 
    delete pb; 
} 

결과는 다음과 B 및 D에 대한

Base::f(double) 
Derived::f(complex) 
Base::f(double) 
10 
Derived::g() 20 
Derived::g() 10 

결과가 예상된다. pb-> f (1.0)은 Base 함수 f (double)를 호출하지만 pb-> g()는 Derived 클래스 함수 g를 호출하지만 Base class에서 i = 10 매개 변수를 사용하는 것처럼 보입니다. 왜?

+2

왜? 'Base' 인터페이스를 정적으로 사용하기 때문에'Derived :: pb'에 대한 디스패치는 런타임에만 발생합니다. –

+0

'delete pb;'는 Base가 가상 소멸자를 가지고 있지 않기 때문에 정의되지 않은 행동을 일으킨다. –

답변

2

Kerrek SB는 모두 의견에 언급 했으므로 좀 자세히 설명하겠습니다.

this answer 에서처럼 기본 함수 매개 변수를 해결하는 메커니즘은 컴파일 타임에 발생합니다. 컴파일러는 pb 유형 Base*의 포인터 것을 알고, pb->g();을 볼 때, 그 그것은 결론

virtual void g(int i = 10); 

입니다 Base::g의 선언을 참조합니다 :

누락 된 매개 변수 i 10로 설정해야합니다

1 이것은 컴파일 타임 결정입니다.

2 메서드는 가상으로 선언됩니다. 즉, 실제로 호출되는 메서드는 런타임에 pb이 가리키는 위치에 따라 달라집니다. 컴파일러는 런타임에 호출을 g으로 디스패치하는 메커니즘을 설정합니다 (일반적으로 vtable을 통한 간접 참조를 통해). 런타임에 pb가 실제로 Derived 유형의 객체를 가리키고 있으므로, Derived::g 메소드가 호출됩니다.