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

编辑:

#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
4

4 回答 4

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
}
于 2010-01-19T09:29:58.287 回答
2

在第一种情况下,类型object在编译时是已知的(假设它不是引用)。所以这将是一个静态绑定。

在第二种情况下,将使用动态绑定,前提是函数是virtual. 否则,静态绑定。

于 2010-01-19T09:08:29.713 回答
1

我认为需要明确的是,第一种情况下的构造函数和析构函数调用是针对未命名的派生对象进行的,它们不是 Var 的构造函数或析构函数。Var 只是一个引用类型,不需要任何特殊处理。由于编译器知道这个未命名的派生对象的类型,它正确地将这些对象静态绑定到派生类。

类似地,构造函数在第二种情况下是静态绑定的,因为 new 后面的类型是派生的。但是,当您对 base 类型的指针调用 delete 时,编译器会调用 Base 的析构函数(同样使用静态绑定)。

如果您将基的析构函数声明为虚拟,那么这个最终绑定 - 删除发生时调用的析构函数将是动态的,并且您将获得与第一种情况相同的输出。

于 2010-01-19T09:56:08.990 回答
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(); 
}

输出:析构函数不是虚拟的,但它被调用了。

于 2010-01-19T10:03:30.820 回答