在C ++中作为参数传递的对象中的方法的执行

时间:2015-08-07 05:07:38

标签: c++ virtual

我有一个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 ++中定义的执行规则?

2 个答案:

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