前段时间在c/c++版块的时候,看到有人问为什么数组对象不支持多态的问题,当时没有回,只是感觉不支持!不能拿出理论和实际证据!后面因为工作也就没有
细想,今天刚好看到酷壳上陈皓老师说的也就来述说一下!
gdb调试结果如下:
(gdb) p pB[1]
$4 = {ptrv = 0x0, a = 135137, c = 0 '\000', d = '\000' <repeats 11 times>}
在子类中,注释 Int d 运行结果如下:
上面的代码可以正确执行,包括调用子类的虚函数!因为内存对齐了。
细想,今天刚好看到酷壳上陈皓老师说的也就来述说一下!
因为这个涉及到内存的问题,所以 我们先来一个小段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语言确实比较强大!学好了它,其他语言都容易融会贯通了!