2010-01-19 2 views
2

아래의 호출이 컴파일 타임에 또는 런타임에 바인딩되는지 여부는 어떻게 결정됩니까?컴파일러에서 함수를 어떻게 해석합니까?

object.member_fn;//object is either base class or derived class object 
p->member_fn;//p is either base class or derived class pointer 

EDITED : 첫 번째 경우

#include <iostream> 
using namespace std; 
class Base 
{ 
     public: 
      Base(){ cout<<"Constructor: Base"<<endl;} 
      ~Base(){ cout<<"Destructor : Base"<<endl;} 
}; 
class Derived: public Base 
{ 
    //Doing a lot of jobs by extending the functionality 
     public: 
      Derived(){ cout<<"Constructor: Derived"<<endl;} 
      ~Derived(){ cout<<"Destructor : Derived"<<endl;} 
}; 
void foo() 
{ 
    Base & Var = Derived(); 
    Base*pVar = new Derived; 
    delete pVar; 
} 
void main() 
{ 
    foo(); 
     std::cin.get(); 
} 


out put: 
Constructor: Base 
Constructor: Derived 
Constructor: Base 
Constructor: Derived 
Destructor : Base // the Derived is not called, 
        // the PVal is of type Base* and the fn is not virtual 
        //so compile time binding 
Destructor : Derived 
Destructor : Base 

답변

8

메서드가 가상이 아니면 컴파일시 두 호출이 모두 해결됩니다. 메서드가 가상이면 질문의 첫 번째 호출 (obj.method())은 개체의 컴파일 타임에 해결되지만 런타임에는 참조를 위해 해결됩니다. 두 번째 호출 (objp->method())은 런타임에 해결됩니다. 컴파일 타임에 강제로 메소드의 파생되지 않은 버전을 호출 할 수도 있습니다.

struct base { 
    void f(); 
    virtual void v(); 
}; 
struct derived : public base { 
    void f(); 
    void v(); // intentionally left virtual out, it does not really matter 
}; 
int main() { 
    derived d; 
    base & b = d; 
    base * bp = &d; 

    // compile time: 
    d.f(); // derived::f 
    d.v(); // derived::v 
    b.f(); // base::f -- non-virtual 
    bp->f(); // base::f -- non-virtual 

    // runtime: 
    b.v(); // derived::v 
    bp->v(); // derived::v 

    // compile time (user forced): 
    b.base::v(); // base::v 
    bp->base::v(); // base::v 
} 
+0

+1 예는 수천 단어에 해당합니다. –

+0

+1,하지만 나는 암묵적으로 첫 번째 호출이 의미하는 바를 이해할 수 없습니다.이 호출은 두 번째 호출 집합과 세 번째 호출 집합에서 첫 번째 호출 집합으로 만들 수 있습니다. – yesraaj

+0

당신이 말한 것들은 컴파일시에 컴파일되도록 실제로 최적화 될 수도 있습니다. 개체에 특정 클래스가 있어야 함을 증명할 충분한 정보와 충분한 지혜가 있다면 가상 호출을 비 가상으로 만들 수 있습니다. 그것들은 원칙적으로 런타임에 해결됩니다. –

2

object 유형은 컴파일 시간에 공지되어있다 (이것은 참고 아니라 가정). 그래서 이것은 정적 바인딩이 될 것입니다.

두 번째 경우에는 함수가 virtual 인 경우 동적 바인딩이 사용됩니다. 그렇지 않으면 정적 바인딩.

+0

참고로 포인터처럼 동작할까요? –

+0

레퍼런스는 컴파일 타임 개념과 런타임 포인터이다. 레퍼런스는 포인터를 사용하지 않고도 참조에 의한 호출 의미를 허용하기위한 것이다. –

+0

@Beginner : 예, 참조는 내부적으로 포인터이므로 포인터처럼 동작합니다. – Tarydon

1

는 나는 이러한 바르의 생성자 또는 소멸자되지 않은 첫 번째 경우의 생성자와 소멸자 호출이 익명의 파생 객체에 만들어진 것이 분명 할 필요가있다 생각합니다. Var는 특별한 처리가 필요없는 참조 유형입니다. 컴파일러는이 명명되지 않은 Derived 객체의 유형을 알고 있으므로 파생 클래스에 올바르게 정적으로 바인딩합니다.

마찬가지로 새 생성자가 파생되기 때문에 두 번째 경우에는 생성자가 정적으로 바인딩됩니다. 그러나 base 유형의 포인터에서 delete를 호출하면 컴파일러는 Base의 소멸자를 다시 호출합니다 (정적 바인딩으로 다시 호출).

기본의 소멸자를 선언 한 경우이 최종 바인딩 - 삭제가 발생할 때 호출 할 소멸자는 동적이며 첫 번째 경우와 동일한 결과를 얻습니다. 임시로 상기 기준 경계 자체가 올바른 소멸자를 호출 한 경우가 있지만

1

동적에만 호출 포인터/참조 및 함수의 경우에 사용되는 결합은,

object.member_fn;//if object is not reference so static binding 
object.member_fn;//if object is reference and member_fn is virtual dynamic binding 
p->member_fn;//p is pointer and member_fn is virtual dynamic binding 

가상이다.

#include <iostream> 
using namespace std; 
//virtual behavior with out the type being polymorphic 
class Base 
{ 
public: Base(){} 
    ~Base(){} 
}; 
class Derived:public Base 
{ 
public:Derived(){} 
     ~Derived(){ 
      std::cout<<"Destructor is not virtual, but it is called"; 
     } 
}; 
void foo(){ 
    Base & bound_to_temporary = Derived(); 
} 
int main(){ 
    foo(); 
    cin.get(); 
} 

출력 : 소멸자가 가상 ​​아니지만, 그것은이라고합니다.

+0

... 컴파일러가 동적 유형을 예측할 수없는 경우 예 : 'std :: string const & foo = "FOO";'이후에 컴파일러는'foo'의 동적 타입을 참조 일지라도 확실히 예측할 수 있습니다. – MSalters

관련 문제