复制对象上的C++动态绑定



我在虚拟函数中遇到了一个问题:以下是一些代码作为示例:

class A
   {
      public : virtual  void print(void)
           {
              cout<< "A::print()"<<endl;
           }
    };
 class B : public A
    {
      public : virtual void print(void)
           {
               cout<<"B::print()"<<endl;
           }
    };
 class C : public A
    {
      public : void print(void)
            {
               cout<<"C::print()"<<endl;
            }
     };
  int main(void)
     {
         A a,*pa,*pb,*pc;
         B b;
         C c;
         pa=&a;
         pb=&b;
         pc=&c;
         pa->print();
         pb->print();
         pc->print();
         a=b;
         a.print();
         return 0;
       }

结果:A: :print()B: :print()C: :print()A: :print()

我知道这是一个多态性,也知道有一个叫做虚拟函数表的表,但我不知道它是如何实现的,还有

   a=b;
   a.print();

结果是:A::print()而不是B::print(,为什么它没有多态性。非常感谢。

对象a仍然是类型A。该赋值只复制来自b的数据,并不使a成为B对象。

这称为对象切片。

a=b;
a.print();

它将打印A::print(),因为a=b会导致对象切片,这意味着a只获得b子对象。阅读:

  • 什么是对象切片

请注意,运行时多态性只能通过指针引用类型实现。在上面的代码中,a既不是指针,也不是reference类型:

A * ptr = &b; //syntax : * on LHS, & on RHS
A & ref =  b; //syntax : & on LHS, that is it!
ptr->print(); //will call B::print() (which you've already seen)
ref.print();  //will call B::print() (which you've not seen yet)

因为a不是指针。它是A的实例,分配a=b;b的实例复制到a。但是函数调用是在A的一个实例上进行的。

执行a = b;时,会对b对象进行切片,即只复制其A部分。多态性只通过指针和引用起作用。搜索"对象切片"以了解该主题。

若要了解有关虚拟方法表的更多信息,请访问wiki。但在一般情况下,该表保留信息方法的地址。因此,表中的类A将有一条记录,说明方法print在地址X中。当您执行pa=&b类b只需将表替换为其一,方法print的地址将指向地址Y。

但当您执行a=b时,您将复制对象。在这种情况下,多态性不起作用。

在类型为A的对象上调用任何成员函数后,仍然有A对象(除了显式析构函数调用,它什么都不留下)。

 a = b;

类实例的赋值只是对名为"operator="的特定成员函数的调用。这里的"operator="没有什么特别之处,只是它的名字是标准的。您可以使用另一个名称进行分配:

a = b;
// you could as well write:
a.assign(b);
// (if such member was defined)

正如您可以编写add(a,b)而不是a+b一样,但a+b更可读。

对函数的显式调用永远不会改变调用它的变量的类型:

A a;
foo(a);
// a is still a A
a.bar();
// a is still a A

声明的a类型是A,不能更改为其他类型:这是a的不变量。

指针也是如此:指向A的类型指针的变量将始终具有指向A的类型指针

void foo (A*&);
A *bar();
A a;
A *p = &a;
foo (p); // might change p
// a still has type: pointer to A
p = bar();
// a still has type: pointer to A

但是p可能指向B类型的对象,因此在运行时,*p的动态类型将是B;但CCD_ 36的动态类型始终为CCD_ 37

相关内容

  • 没有找到相关文章

最新更新