关于基类与派生类之间对象、指针等转化关系的小结

先上一段代码:

#include <iostream>
using namespace std;

//没有使用虚函数的继承派生关系
class Base
{
public:
	Base(int i = 0):ival(i){}
	void getVal()
	{
		cout<<ival<<endl;
	}
private:
	int ival;
};

class Derived:public Base
{
public:
	Derived(int i = 0, int j = 1):Base(i),ival(j){}
	void getVal()
	{
		cout<<ival<<endl;
	}
private:
	int ival;
};

//使用了虚函数的继承派生关系
class Base1
{
public:
	Base1(int i = 0):ival(i){}
	virtual void getVal()
	{
		cout<<ival<<endl;
	}
private:
	int ival;
};

class Derived1:public Base1
{
public:
	Derived1(int i = 0, int j = 1):Base1(i),ival(j){}
	void getVal()
	{
		cout<<ival<<endl;
	}
private:
	int ival;
};


void useBaseObj(Base b)
{
	b.getVal();
}

void useDerivedObj(Derived d)
{
	d.getVal();
}

void useBasePtr(Base *pb)
{
	pb->getVal();
}

void useDerivedPtr(Derived *pd)
{
	pd->getVal();
}

void useBase1Obj(Base1 b)
{
	b.getVal();
}

void useDerived1Obj(Derived1 d)
{
	d.getVal();
}

void useBase1Ptr(Base1 *pb)
{
	pb->getVal();
}

void useDerived1Ptr(Derived1 *pd)
{
	pd->getVal();
}

int main()
{
	Base b;
	Derived d;

	Base *pb = &b;
	Derived *pd = &d;
	useBaseObj(b);//基类实参,基类形参,调用基类函数
	useBaseObj(d);//派生类实参,基类形参,自动转化,调用基类函数
//	useDerivedObj((Derived)b);//无法用基类(自动的)构造出一个派生类
	useDerivedObj(d);//派生类实参,派生类形参,调用派生类函数
	cout<<endl;

	useBasePtr(pb);//指向基类形参,指向基类实参,调用基类函数
	useBasePtr(pd);//指向基类形参,指向派生类实参,调用静态类型-基类函数
//	useDerivedPtr(pb);//指向基类实参,指向派生类形参,无法自动转化
	useDerivedPtr((Derived*)pb);//强制类型转化,打印结果为随机数
								//为什么?
								//因为程序试图访问一个自己并没有的成员
	useDerivedPtr(pd);//指向派生类实参,指向派生类形参,调用派生类
	cout<<endl;

	pb = new Derived;//静态类型为指向基类,动态类型为指向派生类
	useBasePtr(pb);//形参为指向基类指针,实参静态类型为指向基类指针,调用基类函数
	useDerivedPtr((Derived*)pb);//形参类型为指向派生类指针,实参静态类型为指向基类的指针
								//但是由于内存中的确有这个数(因为我们实际new的是一个派生类)
								//所以结果为派生类函数
	cout<<endl;

	Base1 b1;
	Derived1 d1;
	useBase1Obj(b1);//基类实参-基类形参,调用基类函数
	useBase1Obj(d1);//派生类实参-基类形参,发生派生类到基类的转化,调用基类
//	useDerivedObj((Derived)b);//基类实参,派生类形参,无法类型转化,函数报错
	useDerived1Obj(d1);//派生类实参-派生类形参,调用派生类函数
	cout<<endl;

	Base1 *pb1 = &b1;	//b1的实际类型为基类,它的虚函数表指明了如果通过指针或者引用调用自己,使用基类的方法
	Derived1 *pd1 = &d1;//d1的实际类型为派生类,它的虚函数表指明了如果通过指针或者引用调用自己,使用派生类方法
	useBase1Ptr(pb1);	//通过虚函数表查得,对于pb1应该调用基类的方法
	useBase1Ptr(pd1);	//通过虚函数表查得,对于pd1应该调用基类的方法
//	useDerivedPtr(pb1);	//指向基类的实参,指向派生类形参,不匹配
	useDerived1Ptr((Derived1*)pb1);	//通过强制类型转换使其匹配,调用基类函数
									//强制类型转化并没有修改虚函数表的内容,所以还是调用基类的方法


	useDerived1Ptr(pd1);//通过虚函数表查得,调用派生类的方法
	cout<<endl;

	pb1 = new Derived1;	//形参静态类型为基类,动态类型为派生类,虚函数表中指明了遇见它调用派生类函数
	useBase1Ptr(pb1);	//使用派生类方法
	useDerived1Ptr((Derived1*)pb1);//使用派生类方法
	return 0;
}



大部分内容其中注释都说清楚了,下面总结如下:

1.对于基类与派生类对象之间:派生类对象可以用来当做基类对象使用,完成基类的功能,不需要类型转化。反之则不成立,需要一个派生类对象的地方,不能填入一个基类对象。

2.对于指针和引用,分为两种情况:

(a)没有虚函数:此时,调用基类还是派生类完全取决于函数形参的静态类型。如果形参与实参类型不符,需要类型转化:派生类指针转化为基类指针,由编译器自动完成;而基类指针转化为派生类,则必须强制完成。其中后者可能是不安全的。比如我们程序中的那个打印结果为随机数。因为这里试图访问一个基类中并不存在的内容。通常,如果使用C++的类型转化操作:dynamic_cast可以解决这个问题,如果从基类向派生类转化,则会转化失败,dynamic_cast会返回一个空指针;而对应的引用操作则会抛出异常。

(2)有虚函数:此时,函数的调用是通过虚函数表来完成的。每次通过指针或者引用调用它时,都调用的是它实际类型的函数。如果形参与实参类型不符,可以通过强制类型转化来完成匹配,但即使强制类型转化后,并没有改变虚函数表里面的内容,所以不管你如何转化,都调用的它实际指向对象的那个函数。


来源:http://blog.csdn.net/thefutureisour/article/details/8123203

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值