【问题标题】:Why is it called dynamic binding?为什么叫动态绑定?
【发布时间】:2013-05-08 14:58:50
【问题描述】:

我们在Cpp中使用virtual来实现动态绑定,即在运行时根据创建的实际对象而不是引用或指针来决定必须调用哪个函数变量。

class A
{
 int a;
public:
 virtual void show();
};

void A::show() { cout<<a<<endl; }

class B:public A
{
 int b;
public:
 void show() { cout<<b<<endl; }
};

class C:public A
{
 int c;
public:
 void show() { cout<<c<<endl; }
};

假设,someFunction(A&amp; aref)。它可以采用 BCA 类型的对象

注意:假设设置了数据成员的值

我的意思是定义了路径(可以是 A 或 B 或 C)。这不完全是run time dependent [就像要求用户输入年龄并且用户输入一些单词或一些其他数据类型]。

但是为什么将其称为run time binding? 编译器会事先检查要分配的对象是否兼容 或者没有。

是用来表示引用变量与特定类型的对象没有严格关联的术语,它是在运行时决定的。 还有更多吗?

【问题讨论】:

  • 它是动态的,因为虚拟方法调用不能在编译时完全解析(当通过指针或引用调用时);它们只能解析为特定的 vtable 指针。该指针将指向哪个方法在编译时是未知的。
  • “我的意思是定义了路径(可以是 A 或 B 或 C)。” 如果您正在构建库,它也可以是完全不同的类型。在这种情况下,您的库的使用者可以定义他们自己的类型,因此在编译您的库时不可能知道从 A 派生的所有类型的集合。
  • @cdhowie。好的。我没有考虑过它是一个库并在未来拥有派生类。感谢您朝着正确的方向前进

标签: c++ inheritance dynamic virtual language-lawyer


【解决方案1】:

虚拟方法在对象中创建一个virtual table,用于调用方法。

在运行时查找正确的方法。

最明显的情况是,如果您有一个包含不同类型对象的基类列表:

std::list<A*> myList = new std::list<A*>();
myList.push_back(new A());
myList.push_back(new B());
myList.push_back(new C());

for (A* a : myList)
{
    a->show();
}

在这个小例子中,所有对象都是不同类型的,编译器将它们都视为 A 对象(有一个 A 类型的变量调用 show( )),但仍然调用了正确的方法。

【讨论】:

    【解决方案2】:

    编译器不能总是确定变量的确切类型。当您使用基类的指针时,它们可以是任何派生类型。基类指针的派生类型通常只能在运行时解析。

    【讨论】:

      【解决方案3】:

      在其他翻译单元中可以有额外的子类型。此外,即使您考虑在一个批次中编译的所有翻译单元,动态链接也可能在源代码和可以编译它的编译器被狼吃掉数年后引入新的子类型。这确实是在运行时决定的:为调用 virtual 方法而生成的代码从对象(其中的指针)获取函数指针,因此它是一个运行时值,可以取任何值。

      【讨论】:

      • 好的,所以它基于对象中存在的函数指针。这使它成为运行时。
      【解决方案4】:

      您实际上需要在依赖于运行时的上下文中使用一个类才能真正看到后期绑定。

      考虑这样的事情:

      // foo.hpp
      struct A {
      virtual void show();
      virtual ~A();
      };
      struct B : A {
        void show();
      };
      A* get_stuff(std::string x);
      
      // the implementation is in foo.cpp and doesn't interest us here
      
      
      // main.cpp
      #include "foo.hpp"
      int main()
      {
        std::string input;
        // .. read stuff from the user
        A* a = get_stuff(input);
        a->show(); // how would the compiler know which show is being called?
      }
      

      【讨论】:

        【解决方案5】:

        静态绑定和动态绑定的区别在于静态绑定是在编译时定义的——这意味着无论什么类型的对象,它总是会从编译器确定的任何类调用相同的成员函数,并且动态绑定(或运行时绑定)是在代码运行时定义的。这意味着编译器已经生成了代码,这些代码将根据代码所属的类在代码执行时“选择”相应的函数。

        对象显然需要兼容,但编译器不必在编译期间确切知道对象属于哪个类。想象一下,我们有一个程序可以从文件中读取“形状、中心点和大小”,其中 size 只是一个“1-5”,表示超小到超大,以及一个可以创建类对象的函数squarecircletriangle。现在喂它:

        Square 300, 300, 5
        Circle 120, 300, 2
        Circle 240, 300, 2
        Triangle 300, 300, 1
        

        当然,编译器不知道你是要画正方形、圆形还是三角形,或者它们的顺序。每个形状的虚拟“绘制”函数显然是不同的。

        这可能(如果坐标匹配)画出一些看起来像脸的东西(嗯,至少在正方形中有两只眼睛和一个鼻子)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-10
          • 2012-02-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多