C++中的早期和晚期绑定+多态性

Sta*_*ack 3 c++ polymorphism binding

假设没有 Hello 函数,我们只是在 main 中调用 ob.display ,然后它调用 B 类而不是 A 类的显示函数。

函数 display() 的调用由编译器设置为基类中定义的版本一次。这称为函数调用的静态解析,或静态链接——函数调用在程序执行之前就被固定。这有时也称为早期绑定,因为 display() 函数是在程序编译期间设置的。

现在如何在基类中的显示函数之前不使用 virtual 关键字(后期绑定)来调用派生类的显示函数?

现在,在这个程序中,将对象作为按值调用、按指针调用和按引用调用 Hello 函数进行传递都可以正常工作。现在,如果我们使用多态性并希望在调用派生类的成员函数时显示它,我们必须在基类中的显示函数之前添加 virtual 关键字。如果我们通过指针调用和引用调用来传递对象值,它会调用派生类中的函数,但如果我们通过值传递对象,则不会,为什么会这样?>

class A
{
   public:
      void display();                       // virtual void display()
       {
        cout << "Hey from A" <<endl;
       }
};

class B : public A
{
    public:
        void display()
        {
            cout << "Hey from B" <<endl;
        }
};

void Hello(A ob) // &ob  //*ob
{
   ob.display();       // ob->display()
}

int main()
{
    B obj;
    Hello(obj); // obj   //&ob
    return 0;
} 
Run Code Online (Sandbox Code Playgroud)

Mik*_*our 5

现在如何在基类中的显示函数之前不使用 virtual 关键字(后期绑定)来调用派生类的显示函数?

非虚函数只是由编译器根据调用它的对象(或引用或指针)的静态类型来解析。因此,给定一个派生类型的对象以及对其子对象的引用:

B b;
A & a = b;
Run Code Online (Sandbox Code Playgroud)

调用非虚函数会得到不同的结果:

b.display();  // called as B
a.display();  // called as A
Run Code Online (Sandbox Code Playgroud)

如果您知道真实类型,那么您可以指定要调用该版本:

static_cast<B&>(a).display();  // called as B
Run Code Online (Sandbox Code Playgroud)

但如果引用的对象a没有 type ,那就会出现严重错误B

现在,如果我们使用多态性并希望在调用派生类的成员函数时显示它,我们必须在基类中的显示函数之前添加 virtual 关键字。

正确的。如果将函数设为虚拟函数,则即使您使用不同类型的引用或指针来访问它,它也会在运行时根据对象的动态类型进行解析。所以上面的两个例子都将其称为B.

如果我们通过指针调用和引用调用来传递对象值,它会调用派生类中的函数,但如果我们通过值传递对象,则不会,为什么会这样呢?

如果您按值传递它,那么您将对其进行切片:仅复制A对象的一部分,以创建 类型的新对象A。因此,无论该函数是否是虚拟的,在该对象上调用它都会选择版本A,因为它A只是一个A.

如果您通过引用或指针传递,那么您仍然可以访问原始对象及其动态类型B。因此,虚拟函数调用将解析为该B版本。