我该怎么做才能看到静态和动态绑定? [C ++]

时间:2014-11-03 01:40:19

标签: c++ gcc virtual-functions dynamic-binding static-binding

我在Linux上使用GCC。

我希望了解正在运行的虚拟功能。

我应该编写什么样的C ++代码来查看和理解在有和没有虚函数的情况下,静态和动态绑定是如何发生的?

如何“看”他们最终如何受约束以及在此过程中究竟发生了什么?

2 个答案:

答案 0 :(得分:1)

这是一个例子。您可以使用设置为虚函数的函数来构建和运行此代码。要获得虚拟行为,动态分派,动态绑定,请使用定义的预处理器宏IS_VIRTUAL构建它。要查看静态绑定,请在不定义宏的情况下构建它。

#include <iostream>

#if defined(IS_VIRTUAL)
#define CONDITIONAL_VIRTUAL virtual
#else
#define CONDITIONAL_VIRTUAL
#endif

struct A {
  CONDITIONAL_VIRTUAL void foo() { std::cout << "A\n"; }
};

struct B : A {
  CONDITIONAL_VIRTUAL void foo() { std::cout << "B\n"; }
};

// global objects
A a; B b;

enum object_type { get_A, get_B };
A *get_object(object_type t) {
  switch (t) {
    case get_A: return &a;
    case get_B: return &b;
  }
}

int main() {
  std::cout << "Choose A or B: ";
  char c;
  std::cin >> c;

  A *x = get_object( c == 'A' ? get_A : get_B );
  x->foo();
}

绑定与x->foo()的评估相关。编译器必须确定要为该表达式执行的代码。通过静态和动态绑定,编译器查看x并查看其类型为A*,因此它会查看struct A并查找foo()声明。

使用静态绑定,编译器会发现foo()不是virtual,因此编译器会继续执行并生成调用foo()方法的代码。简单。

使用动态绑定,编译器会看到标记为virtual的方法,因此编译器会生成代码,该代码在运行时将使用与对象x关联的函数指针表来选择调用的方法,然后调用找到的任何方法。编译器还在其他位置生成代码,以便为全局ab对象创建表。对于全局a对象,它使表格指向A::foo(),而对于全局b,它使表格指向B::foo()。因此,如果x指向b对象,则表格查找将导致B::foo(),这就是将被调用的函数。

一般情况下,编译器必须确保所有具有虚拟方法的对象都有一个表,指向要调用的正确函数,以便每当对程序可以对象进行虚拟调用时,运行时,获取与该对象关联的表,并查找正确的方法进行调用。

因此,在静态和动态模式下构建上述程序,然后运行它并观察每个输入获得的输出。使用每种输入组合和绑定类型获得的输出填写下表。

       Binding |   static     dynamic
Input
-----
A                    ?           ?
B                    ?           ?

在所有情况下,输出都是通过评估相同的x->foo()方法调用生成的。在哪些情况下是动态绑定的证据?这是否符合您对上述动态绑定解释的理解?

答案 1 :(得分:-1)

class Base {
public:
    int Foo();
    virtual int Bar();
};

class D1 : public Base {
public:
    int Foo();
    virtual int Bar();
};

class D2 : public Base {
public:
    int Foo();
    virtual int Bar();
};

main()
{
    Base * b = (rand() < 100) ? new D1 : new D2;
    // Always calls Base::Foo()
    b->Foo();
    // Call either D1::Bar() or D2::Bar()
    b->Bar();
}