c++中的多态和多态对象模型

1.什么是多态?

多态顾名思义,就是“多种形态”

在c++中,我们是通过虚函数来实现多态的

那么什么是虚函数呢?

虚函数就是在类的成员函数的前面加上virtual关键字,那么该成员函数就是虚函数

在c++中多态形成的条件是什么呢?

1.虚函数的重写;

2.父类的指针或引用调用重写的虚函数。

class A
{
public:
	
        virtual void f1()
	{
		cout<<"A::f1()"<<endl;
	}
};

class B : public A
{
public:
	virtual void f1()
	{
		cout<<"B::f1()"<<endl;
	}
};

void Test()
{
	B b;//b是一个子类对象
	A *p = &b;//此时形成了多态,这个时候调用函数与类型无关,只与指向对象有关,指向谁就调用谁
}
在这里我们进行了虚函数的重写,什么是虚函数的重写呢?

当子类定义了一个和父类完全相同的虚函数(返回值、函数名、可变参数列表)时,则称为重写。

特例:协变 A类虚函数的返回值可定义为A类的指针或引用 B类也是可以定义为B类的。(可以看做是切片类型)

//特例
class A
{
public:
	A* fun()
	{

	}
};
class B : public A
{
public:
	B* fun()
	{

	}
	//此时也构成了重写
};


2.单继承&多继承

1. 单继承:一个类只有一个直接父类时称这个继承关系为单继承
2. 多继承:一个类有两个或以上直接父类时称这个继承关系为多继承

在这里需要了解一下虚表

虚表就是存了虚函数的表

虚函数能够实现多态的重要原因是有一个虚表指针指向了虚函数表,这样就可以通过指针来找到xuhans


单继承

//打印虚表
typedef void(*V_FUNC)(); //定义一个函数指针
void PrintVtable(int* vtable)
{
	printf("vtable 0x%p\n",vtable);
	int** ppvtable = (int**)vtable;
	for(size_t i=0; ppvtable[i]!=0; i++)
	{
		printf("vatable[%u]::0x%p->",i,ppvtable[i]);
		V_FUNC f = (V_FUNC)ppvtable[i];
		f();
	}
}



//单继承
class Base
{
public:
	virtual void fun1()
	{
		cout<<"Base::fun1()"<<endl;
	}
	virtual void fun2()
	{
		cout<<"Base::fun2()"<<endl;
	}
private:
	int _a;
};
class Derive : public Base
{
public:
	virtual void fun1()
	{
		cout<<"Derive::fun1()"<<endl;
	}
	virtual void fun3()
	{
		cout<<"Derive::fun1()"<<endl;
	}
};

int main()
{
	Base b;
	Derive d;
	PrintVtable(*((int**)&b));
	PrintVtable(*((int**)&d));
	return 0;
}
通过调试监视窗口,我们可以发现单继承的对象模型


多继承

//打印虚表
typedef void(*V_FUNC)(); //定义一个函数指针
void PrintVtable(int* vtable)
{
	printf("vtable 0x%p\n",vtable);
	int** ppvtable = (int**)vtable;
	for(size_t i=0; ppvtable[i]!=0; i++)
	{
		printf("vatable[%u]::0x%p->",i,ppvtable[i]);
		V_FUNC f = (V_FUNC)ppvtable[i];
		f();
	}
}
//多继承
class Base1
{
public:
	void virtual Fun1()
	{
		cout<<"Base1::Fun1()"<<endl;
	}
	void virtual Fun2()
	{
		cout<<"Base1::Fun2()"<<endl;
	}
private:
	int _b;
};
class Base2
{
public:
	void virtual Fun1()
	{
		cout<<"Base2::Fun1()"<<endl;
	}
	void virtual Fun3()
	{
		cout<<"Base2::Fun3()"<<endl;
	}
private:
	int _b;
};
class Derive:public Base1,public Base2
{
public:
	void virtual Fun1()
	{
		cout<<"Derive::Fun1()"<<endl;//覆盖
	}
	void virtual Fun3()
	{
		cout<<"Derive::Fun3()"<<endl;
	}
private:
	int _d;
};

int main()
{
	Base1 b1;
	Base2 b2;
	Derive d;
	PrintVtable(*((int**)&b1));
	PrintVtable(*((int**)&b2));
	PrintVtable(*((int**)&d));
	PrintVtable(*((int**)((char*)&d+sizeof(Base1))));
	return 0;
}


多继承及其对象模型


3.菱形虚拟继承


//打印虚表
typedef void(*V_FUNC)(); //定义一个函数指针
void PrintVtable(int* vtable)
{
	printf("vtable 0x%p\n",vtable);
	int** ppvtable = (int**)vtable;
	for(size_t i=0; ppvtable[i]!=0; i++)
	{
		printf("vatable[%u]::0x%p->",i,ppvtable[i]);
		V_FUNC f = (V_FUNC)ppvtable[i];
		f();
	}
}
//菱形继承
class Base
{
public:
	void virtual Fun1()
	{
		cout<<"Base::Fun1()"<<endl;
	}
	void virtual Fun2()
	{
		cout<<"Base::Fun2()"<<endl;
	}
public:
	int _b;
};
class Derive1:virtual public Base
{
public:
	void virtual Fun1()
	{
		cout<<"Derive1::Fun1()"<<endl;
	}
	void virtual Fun3()
	{
		cout<<"Derive1::Fun3()"<<endl;
	}
public:
	int _d1;
};
class Derive2:virtual public Base
{
public:
	void virtual Fun1()
	{
		cout<<"Derive2::Fun1()"<<endl;
	}
	void virtual Fun4()
	{
		cout<<"Derive2::Fun4()"<<endl;
	}
public:
	int _d2;
};
class Derive:public Derive1,public Derive2
{
public:
	void virtual Fun1()
	{
		cout<<"Derive::Fun1()"<<endl;//覆盖
	}

	void virtual Fun5()
	{
		cout<<"Derive::Fun5()"<<endl;
	}
public:
	int _d;
};
int main()
{
	Derive d;
	d._b = 2;
	d._d1 = 3;
	d._d2 = 4;
	d._d = 5;
	PrintVtable(*((int**)&d));
	return 0;

}

菱形虚拟继承的对象模型


这里写图片描述

在我们的菱形虚拟继承中,又有虚表也有虚基表,那么就需要我们在编译代码中看看内存中的状况,在图中我们可以看到,我们把基类的对象存为共有的,因此需要用虚基表用偏移量找到他。这里注意虚函数的重写,因为看的是Derive的对象模型,所以在继承的时候,有的函数进行了重写。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值