多态性奇怪的输出

时间:2014-06-29 07:23:02

标签: c++ oop polymorphism

#include <iostream>
using namespace std;

class base {
public:
    int bval;
    base(){bval=0;}
};

class deri:public base {
public:
    int dval;
    deri(){dval=1;}
};

void SomeFunc(base*arr,int size) {
    for(int i=0;i<size;i++,arr++) {
        cout<<arr->bval;
    }
    cout<<endl;
}

int main() {
    base BaseArr[5];
    SomeFunc(BaseArr,5);
    deri DeriArr[5];
    SomeFunc(DeriArr,5);

    return 0;
}

为什么输出上面的代码呢?

00000

01010

写作时

SomeFunc(DeriArr,5);

会发生什么?基指针如何处理派生对象?

2 个答案:

答案 0 :(得分:6)

你在这里经历了一些切片。基类的大小为(比方说)4,派生类的大小为8.将派生对象数组传递给函数并推进基类指针(通过4个字节的偏移量)产生交替序列0和1。

如果你想保持多态,你应该给你的基类一个虚拟析构函数,并将一个指针数组(例如std :: shared_ptr)传递给你的函数。

<强>插图:

让基础对象包含一个整数:

int bval  

包含两个整数的派生对象:

int bval
int dval

并承诺一个记忆位置保持连续的基础对象:

Offset Value Pointer
 0     0     <- base_pointer
 4     0
 8     0
12     0
16     0

但是传递一个记忆位置来保存衍生对象:

Offset Value Pointer
 0     0     <- base_pointer      <- derived_pointer
 4     1     <- base_pointer + 1  
 8     0     <- base_pointer + 2  <- derived_pointer + 1
12     1     <- base_pointer + 3
16     0     <- base_pointer + 4  <- derived_pointer + 2
...
32     0                          <- derived_pointer + 4
36     1

将基指针前进一个(这意味着4个字节的偏移量), 但不是派生指针,屈服于切片。

答案 1 :(得分:1)

基指针并不真正处理派生对象。通过任何基类来处理对象是合法的,但是一旦你处理基类的代码,它就不再知道它实际上是派生类。

因此,当你增加arr指针时,它会以“base”的大小在内存中移动。实际上它应该以deri的大小递增,但不幸的是它不再知道对象的类型为deri。