以下仅仅是个人分析理解的观点,如有不正确之处,请予指出,多谢!
#include <iostream>
using namespace std;
/*
首先分析 vc++ 在运行期间内存布局
将定义部分 全部放在内存空间中 也可以说先铺下一个结构
理由:根据测试得知 程序一启动 由于加入了int nnnp[102400] 所以该exe占用内存空间加大了400K左右
所以 非声明而是定义 但是这里定义放在内存中的那部分就不清楚了,至少它有大小限制
在做对象定义的时候 比如 B d;
其实是首先将一个内存地址也就是d 放到B的结构内,调用B来的构造函数,以后如果调用其他函数申请了新的内存 都关联到d中
编译过程中 把对象之类的非动态申请内存(new malloc)的语句 也放在了内存空间中
理由: B b3[1]; 写入在main()函数内部,程序一启动的时候 还没有运行到它 内存就增长了
B b;
D *pd = (D*)&b;
pd->vf();
pd->va2();
强制转换后
当调用 vf() 时候 根据查看汇编代码可知
在程序运行内存布局期间,它将所有转跳 都写在一个区域 jump XXX
也就是 布局定义是一个区域 转跳是一个区域
00401XXX 存储的是 class B D C 的定义
00402XXX 存储的是 所有转跳 jump B() ~B() B:vf() D() D:vf()等
pd->vf() 所做的操作是 将pd 所指向的内存地址给寄存器ecx,也就是b的地址
然后调用jump D:vf() 在D:vf() 函数内部 如果需要变量等数据 则根据ecx中传递的地址 去提取 (转跳原理 首先记录下跳之前的地址,在跳到函数内,执行完 在跳回调之前记录的地址中,这个原理就是简单的破解注册)
但是 如果D:vf() 仅仅是cout<<"aa" 之类的话 跟数据地址无关,则直接执行。(这里先不加入虚函数的概念)
pd->va2();
这里是要输出i1 虽然D没有实例化 但是B实例化了 并且这个函数输出i1的数据地址B能够给出 所以可以执行
举个更明显的例子:
C* pc = NULL;
pc->vfc();
pc->vfc2(); vfc2中存在了变量 如果想正常执行 就必须给他定义成为静态成员函数,呵呵这就是静态的好处
*/
class B
{
public:
int nnnp[102400];
int i1;
B()
{
i1 = 11;
cout << "构造 B" << endl;
cout<<i1<<endl;
cout<<&i1<<endl;
}
void vf()
{
cout << "This is class B" << endl;
}
virtual ~B()
{
cout << "析构 B" << endl;
}
};
class D: public B
{
public:
// int i1;
D()
{
i1 =2;
cout << "构造 D" << endl;
cout<<i1<<endl;
}
void vf()
{
cout << "This is class D" << endl;
}
void va()
{
cout << "This is class D va" << endl;
}
void va2()
{
cout <<i1<< endl;
cout<<&i1<<endl;
}
~D()
{
cout << "析构 D" << endl;
}
};
class C
{
public:
void vfc()
{
cout<<"Class c"<<endl;
}
static void vfc2()
{
char p = 'c';
cout<<"Class c:"<<p<<endl;
}
};
main()
{
cin.get();
B b;
// cout<<&b<<endl;
D *pd = NULL;
pd = (D*)&b;
// cout<<&pd<<endl;
pd->vf();
pd->va2();
C* pc = NULL;
pc->vfc();
pc->vfc2();
B b3[1];
// char *p = new char[10240];
cin.get();
}
/*
疑问1
pb = &d; 不需要转换
即可指向d的地址
原因 d是b的继承类 按照继承类的特性 d的覆盖范围包含b
所以pb 可调用的函数 都是b中的 并且d中指定都含有了 所以 没问题
以下理解错误
pd = (D*)&b; 需要转换
即不可指向b的地址
原因pd是d的指针,可以调用b中及d的方法,但是d中的方法b中不一定全部含有
所以必须需要转换一下
正确: 强制转换 就是强制转换 不关心数据类型
疑问2
在非多态前提下
pb = &d;
pb->vf();
输出结果是 b
是否可以这样理解: 指针或对象 决定了它的 活动范围,
限制:
B的指针或对象 就只能在B类范围内活动
D的指针或对像 就只能在D类范围内活动
虽然D.vf函数 覆盖了B.vf()
但是由于限制前提 所以 pb 输出仍然是b
以上太牵强了
问题2解决 看开头叙述部分
*/