虚拟功能有问题: 以下是一些代码示例:
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;
}
结果: 打印() B ::打印() Ç::打印() A ::打印()
我知道这是一个多态,并且知道有一个名为virtual-function-table的表,但我不知道它是如何实现的,并且
a=b;
a.print();
结果是:A :: print()不是B :: print(),为什么它没有多态性。 谢谢!
答案 0 :(得分:5)
对象a
仍为类型 A
。该作业仅复制b
的数据,而不会使a
成为B
个对象。
这称为object slicing。
答案 1 :(得分:2)
a=b;
a.print();
它将打印A::print()
,因为a=b
会导致对象切片,这意味着a
只会获得b
的 a-subobject 。阅读本文:
请注意,运行时多态性可以通过指针和引用类型实现 。在上面的代码中,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)
答案 2 :(得分:1)
因为a
不是指针。它是A
的一个实例,作业a=b;
将<{1}}的实例复制到b
。但是函数调用是在a
。
答案 3 :(得分:1)
执行a = b;
时,b
对象被切片,即仅复制A
部分。多态性只能通过指针和引用来实现。搜索“对象切片”以了解该主题。
答案 4 :(得分:0)
要了解有关虚拟方法表的更多信息,请参阅wiki。但在一般情况下,表保留信息方法的地址。因此,表中的A类将有一条记录表示方法 print 位于地址X中。当您执行 pa =&amp; b B类时,只需将表替换为一个方法 print 的地址将指向地址Y。
但是当你执行 a = b 时,你会复制对象。在这种情况下,多态不起作用。
答案 5 :(得分: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
声明的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
;但动态类型p
始终为A*
。