我有一个Rabbit结构,以及继承它的CrazyRabbit结构。 当我执行此代码时:
#include <iostream>
using namespace std;
struct Rabbit {
virtual void sayCry() {
cout << "..." << endl;
}
};
struct CrazyRabbit : Rabbit {
void sayCry() { cout <<"Moo"<< endl; }
};
void foo(Rabbit r, Rabbit* pr, Rabbit& rr) {
r.sayCry();
pr->sayCry();
rr.sayCry();
}
int main(int argc, char *argv[]) {
Rabbit *pr = new CrazyRabbit();
foo(*pr, pr, *pr);
}
我有结果:
...
Moo
Moo
为什么第一种情况在超类中执行方法?是否有在C ++中定义的执行规则?
答案 0 :(得分:1)
foo()的第一个参数类型不是指针,你实际做的是复制到超类的一个实例。这是因为当您实际调用函数时,每个函数参数都会使用您提供的任何参数进行初始化。所以,好像你做了以下事情:
Rabbit r = *pr; // (from your main()) object slicing happens here
Rabbit* pr = pr; // (the rhs pr is from your main(), not the pr from foo())
Rabbit& rr = *pr; // (from your main())
因此,在第一种情况下,您只是声明一个Rabbit类型的对象并分配其派生类,这会导致对象切片,这意味着属于派生类CrazyRabbit的任何数据都将丢失,并且剩下的唯一数据是那种兔子类型。
对于虚函数调用,您需要一个指针。在运行时,C ++将检查vptr和vtbl以正确识别要调用的虚拟函数。
答案 1 :(得分:1)
这叫做&#34;对象切片&#34; ,你实际做的是将一个指向派生类对象的指针分配给基类类型,编译器会切掉这些东西所以它与基类类型匹配。
因为这里基类对派生类的函数cry()
一无所知,所以它会将其分割掉,之后编译器只能看到基类{{1} }。
在这个例子中:虽然你可能认为objA会有a,b&amp; c但是&#34; c&#34;衍生文件由编译器切片。它被称为 UpCasting 。
cry()