0

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

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()

我知道这是一个多态,并且知道有一个名为 virtual-function-table 的表,但我不知道它是如何实现的,并且

   a=b;
   a.print();

结果是:A::print() 不是 B::print(),为什么它没有多态性。谢谢你!

4

6 回答 6

5

该对象a仍然是type A。该分配仅从 复制数据b,它不会创建a对象B

这称为对象切片

于 2012-07-30T08:51:08.110 回答
2
a=b;
a.print();

它将打印A::print(),因为会导致对象切片,a=b这意味着a仅获取. 读这个 :b

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

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)
于 2012-07-30T08:50:41.970 回答
1

因为a不是指针。它是 的实例A,并且赋值a=b; 复制b了to的实例a。但是函数调用是在A.

于 2012-07-30T08:51:12.990 回答
1

当你这样做时,a = b;b的对象被切片,即只有A它的一部分被复制。多态性仅通过指针和引用起作用。搜索“对象切片”以了解该主题。

于 2012-07-30T08:51:50.953 回答
0

要了解有关虚拟方法表的更多信息,请参阅wiki。但在一般情况下,该表保留了信息方法的地址。因此,表中的 A 类将有一条记录表明方法print位于地址 X。当您执行pa=&b时, B 类只需将表替换为它的一个,这样方法print的地址将指向地址 Y。

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

于 2012-07-30T08:56:17.443 回答
0

在对类型的对象调用任何成员函数之后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

声明的类型aA,并且不能更改为其他类型:这是 的不变量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; 但动态类型p始终是A*.

于 2012-08-08T19:31:12.080 回答