关闭

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

2042人阅读 评论(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' <repeats 11 times>}

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

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

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

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


#include <iostream>
using namespace std;

class Base
{
    public:
        int b;
        virtual ~Base()
        {   
            cout <<"Base::~Base()"<<endl; 
        }   
};

class Derived : public Base
{
    public:
//      int d;  //  注意这个地方,先是注释的,打开的运行又是怎么样的呢?
        virtual ~Derived() { 
            cout <<"Derived::Derived~()"<<endl; 
        }   
};
int main(void)
{
    cout << "size base    = " << sizeof(Base) << endl;
    cout << "size Derived = " << sizeof(Derived) << endl;
    
    Base *pB = new Derived [2];

    delete [] pB; 

    return 0;
}

在子类中,注释 Int d 运行结果如下:


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语言确实比较强大!学好了它,其他语言都容易融会贯通了!



4
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:156881次
    • 积分:2469
    • 等级:
    • 排名:第16393名
    • 原创:47篇
    • 转载:3篇
    • 译文:0篇
    • 评论:288条
    博客专栏
    博客公告
    一步一个脚印的学习技术,并分享技术。 相互交流才能更好的促进学习的进度。如发现有疑惑,请及时指出,我和其他读者表示衷心的感谢。博客内容欢迎大家各种转载,但是请注明文章出去,不可作为商业用途。---- -- Python交流群:316286565 --安防协议交流群:163345590
    最新评论