C++中的多态之父类指针调用子类对象的虚函数失败,与子类、父类占用的内存大小以及指针步长的关系

原来使用父类和子类指针都指向子类对象,然后调用虚函数,但是在子类对象中加入一个int i;属性之后,宕机了。

这是因为,父类指针p和子类指针c(加入int i之后),两个类所占的内存大小也不一样了,指针的数据类型是他所指向的内存空间的数据类型,因此p指针自加1的大小为一个父类对象的内存大小,而c指针自加1的大小为一个子类对象的大小。

p与c的指针步长不一样。

此时仍想利用p指针实现多态,而p++之后,p类指针增加的内存大小(p指针的偏移量)是一个父类对象的大小,指向的是数组中第一个子类对象的新增成员变量int i;而不是VPTR指针,此时若使用指针p调用虚函数(来实现多态),则会宕机。

 

 

 

原理:指针作为一种数据类型,它的数据类型是由其指向的内存空间的数据类型决定的。

而在使用子类数组,用for循环,使得子类对象挨个实现多态是没有问题的。

但别用父类指针p指向该子类对象数组的首地址,再用p++,这样就因为指针步长不一样产生错误或者异常而宕机。

简而言之,不要用父类指针做辅助变量,去遍历基类的数组。

 

当子类和父类中,除了虚函数相同以外,还有各自的成员变量,其他函数时,这时候子类和父类占用的内存大小是不同的。因此,当使用父类指针实现多态时,要注意:当父类指针指向的是子类对象数组时,此时执行父类指针pBase++,指针移动的步长(及内存大小)仍然为父类的占用的字节大小,而子类中可能有新定义的成员变量和成员函数等,此时pBase指向的不一定是子类的虚函数的地址了,假设指向了子类的成员,这是用pBase指针调用虚函数时,就会宕机,报错。

#include "iostream"
using namespace std;

//指针也是一种数据类型,指针数据的数据类型是指,它所指的内存空间的数据类型
//最后一点引申 指针的步长 。。。c++

class Parent001
{
protected:
	int i;
	int	j;
public:
	virtual void f()
	{
		cout << "Parent001::f" << endl;
	}
};


class Child01 : public Parent001
{
public:
	int k;
public:
	Child01(int i, int j)
	{
		printf("Child01:...do\n");
	}

	virtual void f()
	{
		printf("Child01::f()...do\n");
	}
};

void howToF(Parent001 *pBase)
{
	pBase->f();
}

//指针的步长 在c++领域仍然有效,父类指针的步长和子类指针的步长不一样
//多态是靠迟绑定实现的(vptr+函数指针实现)
int main006()
{
	int i = 0;
	Parent001* p = NULL;
	Child01* c = NULL;

	//不要把父类对象还有子类对象同事放在一个数组里面
	Child01 ca[3] = { Child01(1, 2), Child01(3, 4), Child01(5, 6) };

	//不要用父类指针做赋值指针变量,去遍历一个子类的数组。

	p = ca;
	c = ca;

	p->f();
	c->f(); //有多态发生

	p++;
	c++;
			 
	//p->f();//基类对象与子类对象的大小不一样,导致p++后指向的是子类中的成员变量k,而不是函数f()
	c->f();

	for (i = 0; i<3; i++)
	{
		howToF(&(ca[i]));
	}


	system("pause");
	return 0;
}

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页