从内存上解析c++中数组为什么不支持多态

2014-11-24 03:04:36 · 作者: · 浏览: 1
前段时间在c/c++版块的时候,看到有人问为什么数组对象不支持多态的问题,当时没有回,只是感觉不支持!不能拿出理论和实际证据!后面因为工作也就没有
细想,今天刚好看到酷壳上陈皓老师说的也就来述说一下!

因为这个涉及到内存的问题,所以 我们先来一个小段c语言简单代码

typedef struct 
{
    void *ptrv;
    int  a;  
    char c;
}Base_t;

typedef struct 
{
    void *ptrv;
    int a;
    char c;
    char d[12];
}Derived_t;

int main(void)
{
    Derived_t stB[2] = { 
        {(void*)0x01, 100, 'd', "Derived0"}, 
        {(void*)0x02, 200, 'D', "Derived1"}
    };  
    Base_t *pA = (Base_t *)stB;

//  Base_t *pA = (Base_t *)malloc(2 * sizeof(Base_t));
//  pA[0].ptrv = (void*)0x3;
//  pA[0].a    = 1000;
//  pA[0].c    = 'a';
//
//  pA[1].ptrv = (void*)0x4;
//  pA[1].a    = 2000;
//  pA[1].c    = 'A';
//  Derived_t *pB = (Derived_t *)pA;
    return 0;
}
通过gdb调试看到栈上的数据情况

(gdb) p stB
$4 = {{ptrv = 0x1, a = 100, c = 100 'd', d = "Derived0\000\000\000"}, {ptrv = 0x2, a = 200, c = 68 'D', d = "Derived1\000\000\000"}}
(gdb) p pA[0]
$5 = {ptrv = 0x1, a = 100, c = 100 'd'}
(gdb) p pA[1]
$6 = {ptrv = 0x64657669, a = 48, c = 0 '\000'}
(gdb) q
A debugging session is active.

很明显,pA[0]的还是正确,但是pA[1]的值已经完全被破坏掉了!

上面的例子已经能说明一个部分的原因了,我们再改把main函数里面注释打开,把上面的注释掉再看看

int main(void)
{
//  Derived_t stB[2] = {
//      {(void*)0x01, 100, 'd', "Derived0"}, 
//      {(void*)0x02, 200, 'D', "Derived1"}
//  };
//  Base_t *pA = (Base_t *)stB;

    Base_t *pA = (Base_t *)malloc(2 * sizeof(Base_t));
    pA[0].ptrv = (void*)0x3;
    pA[0].a    = 1000;
    pA[0].c    = 'a';

    pA[1].ptrv = (void*)0x4;
    pA[1].a    = 2000;
    pA[1].c    = 'A';
    Derived_t *pB = (Derived_t *)pA;
    return 0;
}

gdb调试结果如下:

(gdb) n
53		return 0;
(gdb) p pA[0]
$1 = {ptrv = 0x3, a = 1000, c = 97 'a'}
(gdb) p pA[1]
$2 = {ptrv = 0x4, a = 2000, c = 65 'A'}
(gdb) p pB[0]
$3 = {ptrv = 0x3, a = 1000, c = 97 'a', d = "\000\000\000\004\000\000\000\320\a\000\000A"}
(gdb) p pB[1]
$4 = {ptrv = 0x0, a = 135137, c = 0 '\000', d = '\000' 
  
   }

  

(gdb) p pB[1]
$4 = {ptrv = 0x0, a = 135137, c = 0 '\000', d = '\000' }

很明显,pB[1]的值,也完全被破坏了!

可见,这完全就是C语言里乱转型造成了内存的混乱,这和C++一点关系都没有。

而且,C++的任何一本书都说过,父类对象和子类对象的转型会带来严重的内存问题。
那我们接下来看看c++的例程:

#include 
   
    
using namespace std;

class Base
{
    public:
        int b;
        virtual ~Base()
        {   
            cout <<"Base::~Base()"<
    
      size base = 8 size Derived = 8 Derived::Derived~() Base::~Base() Derived::Derived~() Base::~Base() 
    
   
不注释 int d 运行结果如下:

size base    = 8
size Derived = 12
Segmentation fault

上面的代码可以正确执行,包括调用子类的虚函数!因为内存对齐了。

但是如果打开屏蔽的int成员的话,这个程序就Segmentation fault了。

pB[1]的虚表找到了一个错误的内存上,内存乱掉了。

所以通过上面的一个c语言的基本例程和一个c++的例程,大家就可以完全理解为什么c++中数组不支持多态了吧!

从内存这边来分析,这个完全就是c语言的内存管理知识,和c++语言本身一点关系都没有的,如果对c语言内存管理这块熟悉的话,

一眼就知道内存在其中作祟了!所以从c++很多东西也可以看出,c语言确实比较强大!学好了它,其他语言都容易融会贯通了!