多态性奇怪的输出

Polymorphism wierd Output

本文关键字:输出 多态性      更新时间:2023-10-16
#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);

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

您在这里经历了一些切片。基类的大小为(比方说)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

并将基指针移动1(这意味着偏移量为4字节),但不是派生指针,它屈服于切片。

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

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