C++多态——(c+要笑着学)

本文探讨了C++中的多态概念,包括多态的构成条件,如虚函数和重写。讲解了如何通过基类指针调用虚函数实现多态,并提到了抽象类和多态原理,最后总结了多态的关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

🎶多态的概念

🎶多态的定义及实现

✨多态的构成条件

✨在继承中实现多态的必要条件

✨虚函数

✨虚函数重写

Exception:

✨override And final

✨重写,重载,隐藏的比较

 🎶抽象类

🎶多态的原理

✨summary


csnd

🎶多态的概念

      多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态

比如我们在乘公交车的时候使用的公交卡,学生上面就会显示一下~~bi学生卡,老人就会bi一下,老年卡,bibi~~~。那么你有想过为什么同为一张卡为什么他的就会是学生卡,而你却往里面塞硬币呢,或者说你的卡没有bibi呢~~~。这里就涉及到多态问题,那么这么多形态它是怎么是实现的呢?

🎶多态的定义及实现

✨多态的构成条件

    多态是在使用派生类对象继承了一个对象之后,基类和派生类对象同样去调用同一个函数,函数实现的功能不一样。一个比较形象的例子。比如儿子这个对象继承了父亲对象,然后这两个对象都去找母亲要零花钱,身份不一样要过的零花钱肯定就不一样了吧~~~~

✨在继承中实现多态的必要条件

  1. 必须通过基类的指针或者引用来调用虚函数
  2. 被调用的函数必须是虚函数,且派生必须和基类的虚函数完成重写

✨虚函数

    被virtual修饰的类成员函数称为虚函数~~

✨虚函数重写

     虚函数的重写 ( 覆盖 ) 派生类中有一个跟基类完全相同的虚函数 ( 即派生类虚函数与基类虚函数的返回值类 型、函数名字、参数列表完全相同 ) ,称子类的虚函数重写了基类的虚函数。

Exception:

      派生类对象函数起那面不加virtual关键字,返回值,函数名称,参数相同。也构成重写。最好还是加上~~

  • 协变:派生类对象虚函数和基类虚函数返回值不同也构成多态,称之为协变。
class Father
{
public:
	virtual Father* Mom()
	{
		cout << "Get Out of my sight~" << endl;
		return  new Father;
	}
};
class Son :public Father
{
private:
	 virtual Son* Mom()
	{
		cout << "My dear son" << endl;
		return new Son;
	}
};
  • 析构函数的多态:析构函数名字不同但但是也构成多态,是因为析构函数在析构时会在底层调用destructor。做了统一处理。所以也构成协变。

     这里我们看多多调用了一次基类的析构函数是因为派生类在有构造函数,或者析构函数时,基类部分的变量调用基类的构造或者析构函数~~~

✨override And final

    override检查派生类是否重写基类虚函数,如果没有就报错~~~

       final定义基类不可以再被继承~~~~~

✨重写,重载,隐藏的比较

 🎶抽象类

    在虚函数后面加上=0;那么这个函数就为纯虚函数,包含纯虚函数的类称之为抽象类,抽象类不可以实例化出对象,被继承之后派生类也不可以实例化出对象,只有派生类也重写纯虚函数才可以实例化出对象~~

🎶多态的原理

class A
{
public:
	virtual void Func()
	{
		cout << "hello world" << endl;
	}
private:
	int a;
	char c;
};
int main()
{
	cout << sizeof(A) << endl;
	return 0;
}

    经过检验A类大大小为12个字节,那么肯定这里的虚函数就有占位的可能。其实就是虚函数的作用,虚函数会生成一个虚函数指针放在对象的第一个位置,那么在32位系统中指针大小为4个字节。就占用了前四个字节地址~~~

     我们称a对象下面虚函数所生成的为虚函数表指针,而这个指针所指向的就是多态形成的关键所在~~~


class A
{
public:
	virtual void Func()
	{
		cout << "hello world" << endl;
	}
	void Funcn(A& a)
	{
		a.Func();
	}
private:
	int a;
	char c;
};
class B:public A
{
public:
	virtual void Func()
	{
		cout << "yes" << endl;
	}
};
int main()
{
	A a;
	a.Funcn(a);
	B b;
	b.Funcn(b);
	return 0;
}

    我们定义了一个派生类去继承基类

     我们发现虽然派生类要去继承基类的成员,但是虚表指针却不是继承过来的,每个类里面都有自己的虚表指针。每个对象的虚表指指针再去调用自己的虚函数~~我自己是这样理解的。

✨summary

    

1. 派生类对象 d 中也有一个虚表指针, d 对象由两部分构成,一部分是父类继承下来的成员,虚表指针也就是存在部分的另一部分是自己的成员。
2. 基类 b 对象和派生类 d 对象虚表是不一样的,这里我们发现 Func1 完成了重写,所以 d 的虚表中存的是重 写的 Derive::Func1 ,所以虚函数的重写也叫作覆盖 ,覆盖就是指虚表中虚函数的覆盖。重写是语法的叫法,覆盖是原理层的叫法。
3. 另外 Func2 继承下来后是虚函数,所以放进了虚表, Func3 也继承下来了,但是不是虚函数,所以不会放进虚表。
4. 虚函数表本质是一个存虚函数指针的指针数组,一般情况这个数组最后面放了一个 nullptr
5. 总结一下派生类的虚表生成: a. 先将基类中的虚表内容拷贝一份到派生类虚表中 b. 如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c. 派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这里关于多继承虚函数表解析🔨功力还没有那么深!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值