C++:多态

C++基础:什么是C++的多态性 多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphisn),字面意思多种形状。 C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写。(这里我觉得要补充,重写的话可以有两种,直接重写成员函数和重写虚函数,只有重写了虚函数的才能算作是体现了C++多态性)而重载则是允许有多个同名的函数,而这些函数的参数列表不同,允许参数个数不同,参数类型不同,或者两者 阅读详情

多态

一、多态的概念

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

举个栗子吧: 比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。

想要定义出多态需要有这两个条件:

  1. 调用函数的对象必须是指针或者引用
  2. 父类和子类中被调用的函数必须是虚函数(在函数前面加上virtual关键字),完成虚函数的重写,重写就是要函数完全相同,包括返回值,函数名,参数。重写也叫做覆盖。

如下代码,就实现了买票的多态:

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "成人买票:全价" << endl;
	}
};
class Student :public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "学生买票:半价" << endl;
	}
};
void Buy(Person& p)
{
	p.BuyTicket();
}
int main()
{
	Person p;
	Student s;
	Buy(p);
	Buy(s);
	return 0;
}

具体调用过程如下:
在这里插入图片描述
打印结果:
在这里插入图片描述

虚函数的重写的例外情况
  1. 协变
    虚函数的重写返回值可以不同,但是必须是基类指针和派生类指针或者是基类引用和派生类引用。这种协变一般很少使用。
class A{};
class B : public A {};
class Person {
public:
	virtual A* f() { return new A; }
};
class Student : public Person {
public:
	virtual B* f() { return new B; }
};
  1. 不规范的多态写法
    父类中是虚函数,子类中不是虚函数,也构成多态。因为多态其实是基于继承的一个操作,子类会继承父类的成员函数和成员变量。
    但是如果子类有虚函数,父类没有虚函数,那么就不构成虚函数,会构成隐藏(重定义)。
class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "成人买票:全价" << endl;
	}
};
class Student :public Person
{
public:
	void BuyTicket()
	{
		cout << "学生买票:半价" << endl;
	}
};

二、析构函数的多态

基类的析构函数一般都建议定义为虚函数,因为不构成多态要看它的类型,如果是多态看的是对象。

比如下面这个特殊情况,一个父类的指针有可能指向一个父类对象,也有可能指向一个子类对象,那么当它进行释放的时候是会根据对象调用它的析构函数的,那也就是说如果是一个父类的对象就要去掉父类的析构,如果是一个子类的对象就要去掉子类的析构,那么也就是说不同的对象去调就会有不同的结果!!啊啊!!那这不就是多态么!

所以当我们把父类的析构定义为虚函数的时候,因为继承的关系,所以子类的析构函数也会变成虚函数,父类的析构和子类的析构就会构成重写,就构成了多态。因此如果一个父类的指针指向子类的对象的时候也不用担心了,构成多态的时候是根据类型来进行调用的,是子类对象来调用所以必然会去调用子类的析构函数。

有盆友可能会疑问:~Person()和~Student()怎么能构成多态呢?这俩函数名都不一样啊!其实编译器底层会把析构函数都命名为destructor,所以其实他们俩其实是同名的哈哈。

class Person {
public:
	virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:
	~Student() { cout << "~Student()" << endl; }
};
int main()
{
	Person* p = new Student;//父类的指针指向子类对象
	delete p;
	return 0;
}

三、抽象类

抽象类就是含有纯虚函数的类,纯虚函数就是在父类的虚函数后面写上=0。

抽象类是不能定义出对象的,就算派生类继承了这个类也不能定义出对象,只有派生类通过对该纯虚函数的重写之后,才能定义出对象。所以抽象类是为了完成强制重写的类,它体现了接口继承。

接口继承和实现继承:
普通函数的继承是一种实现继承。 一个子类继承了父类,那么父类中的函数在子类中也可以使用,它继承的是函数的实现。
虚函数的继承是一种接口继承。 一个子类继承了父类,如果父类中含有虚函数,那么子类继承的是父类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。

class Car//不能实例化出对象
{
public:
	virtual void Drive() = 0;//纯虚函数
};
class Benz :public Car
{
public:
	virtual void Drive()//完成重写,构成多态
	{
		cout << "Benz-舒适" << endl;
	}
};
class BMW :public Car
{
public:
	virtual void Drive()//完成重写,构成多态
	{
		cout << "BMW-操控" << endl;
	}
};

纯虚函数的作用:

  1. 实现抽象类
  2. 体现接口继承
  3. 强制重写

四、C++11 override 和 final

C++11中引入了两个关键字来修饰虚函数。

override:修饰派生类虚函数强制完成重写,如果没有重写会编译报错
override可以用于检查派生类是否完成了重写。

class Car{
public:
	virtual void Drive(){}
};
class Benz :public Car {
public:
	virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

final:被final修饰过的虚函数被继承以后无法完成重写

class Car
{
public:
	virtual void Drive() final {}
};
class Benz :public Car
{
public:
	//报错,提示无法完成重写
	//virtual void Drive() 
	//{ 
	//	cout << "Benz-舒适" << endl; 
	//}
};

五、多态的原理

首先看下面这个代码,这个Base占用多少字节呢?

class Base
{
public:
	virtual void Func1()
	{
		cout << "Func1()" << endl;
	}
private:
	int _b = 1;
};

通过在32位平台下验证我们发现结果是8。
在这里插入图片描述
查看监视窗口我们发现这里有一个_vfptr,这个叫做虚表指针,存的是虚函数表的地址。一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数的地址要被放到虚函数表中,虚函数表也简称虚表。

如果被继承之后会怎么样呢?我们再接着验证。

class Base
{
public:
	virtual void Func1()
	{
		cout << "Base::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base::Func2()" << endl;
	}
	void Func3()
	{
		cout << "Base::Func3()" << endl;
	}
private:
	int _b = 1;
};
class Derive : public Base
{
public:
	virtual void Func1()
	{
		cout << "Derive::Func1()" << endl;
	}
private:
	int _d = 2;
};
int main()
{
	Base b;//8
	cout << sizeof(Base) << endl;
	Derive d;//12
	cout << sizeof(Derive) << endl;
	return 0;
}

这里Base的大小是8(一个虚表指针4,一个成员变量_b是4,4+4=8)
Derive的大小是12(一个虚表指针4,一个继承下来的成员变量_b是4,一个成员变量_d是4,4+4+4=12)
在这里插入图片描述
这里的Fun1和Fun2是虚函数,会被继承到虚函数表里,但是Fun1在子类中完成了重写,所以首先d里面有一个虚表指针,另外Fun3也被继承下来了,但是因为不是虚函数,所以不会放在虚表中,就是普通成员函数的继承。b中的_b被继承下来,另外d自己还有一个成员变量_d。

派生类虚表的生成:

  1. 先把父类的虚表拷贝过来
  2. 判断有没有重写的情况,如果有直接对某函数覆盖
  3. 看子类中还有没有虚函数,如果有就补在子类虚函数表的后面,有几个就补几个
虚函数存在哪的?虚表存在哪的?

虚函数其实和普通的函数一样,都是成员函数,都存在代码段的,只是虚函数的地址会被保存在虚表中。另外对象中存的不是虚表,而是虚表指针。
那么虚表又存在哪里呢?
我们可以写一段代码进行验证:

int main()
{
	Base base;
	int a;//栈
	int* b = new int;//堆
	static int c;//静态区
	char* d = "abcd";//代码段

	cout << &a << endl;
	cout << b << endl;
	cout << &c << endl;
	cout << (void*)d << endl;

	cout << (void*)(*(int*)&base) << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
首先我们分析堆栈是不可能的,因为虚表指针在程序编译好的时候是不会改变的,栈上存放的是局部变量,出了作用域会被销毁,因此排除栈。堆是进行动态开辟的区域,因此排除堆。静态区的数据要不就是静态数据要不就是全局数据,因此分许出来放在代码段最为合适。并且通过代码验证,发现虚表指针的地址和代码段的d的地址非常接近,因此可以断定在代码段。

多态的原理

再返回看我们写的买票函数

  1. 观察下图的红色箭头我们看到,p是指向mike对象时,p->BuyTicket在mike的虚表中找到虚函数是Person::BuyTicket。
  2. 观察下图的蓝色箭头我们看到,p是指向johnson对象时,p->BuyTicket在johson的虚表中找到虚函数是Student::BuyTicket。
  3. 这样就实现出了不同对象去完成同一行为时,展现出不同的形态。
  4. 反过来思考我们要达到多态,有两个条件,一个是虚函数覆盖(重写),一个是对象的指针或引用调用虚函数。
    在这里插入图片描述

普通调用:静态联编(编译时决议)
多态调用:动态联编(运行时决议)

多态是一种动态联编,它是在程序运行起来的时候,调用对应函数时去虚表里面查找的,找到地址之后再去call调用它。

我们通过汇编语言再来了解一下多态调用。
在这里插入图片描述

六、单继承和多继承关系的虚函数表

单继承中的虚函数表
class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};
class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
private:
	int b;
};
int main()
{
	Base b;
	Derive d;
	return 0;
}

根据我们了解的多态的知识,我们分析上面的代码可以得出,Derive里会将func1重写,然后将Base里的func2继承下来,另外再补上自己的func3和func4。我们调用监视窗口进行查看:
在这里插入图片描述
咦?我们发现只有重写的func1和继承下来的func2,而没有Derive里面自己的func3和func4,这是为什么呢?这是因为编译器对它进行了优化。那么我们可以自己写一段代码来打印Derive的虚函数表。

思路:取出b、d对象的头4个字节,就是虚表的指针,前面我们说了虚函数表本质是一个存虚函数指针的指针数组,这个数组最后面放了一个nullptr

  1. 先取b的地址,强转成一个int*的指针
  2. 再解引用取值,就取到了b对象头4个字节的值,这个值就是指向虚表的指针
  3. 再强转成VFUNC*,因为虚表就是一个存VFUNC类型(虚函数指针类型)的数组。
  4. 虚表指针传递给PrintVTable进行打印虚表
  5. 需要说明的是这个打印虚表的代码经常会崩溃,因为编译器有时对虚表的处理不干净,虚表最后面没有放nullptr,导致越界,这是编译器的问题。我们只需要点目录栏的-生成-清理解决方案,再编译就好了。
typedef void(*VFUNC)();//定义一个函数指针VFUNC

void PrintVTable(VFUNC* table)
{
	cout << "虚表" << table << endl;
	for (int i = 0; table[i] != nullptr; i++)//虚表的最后一个元素是nullptr
	{
		printf("虚函数%d : [0x%p]->", i, table[i]);
		table[i]();
	}
}

int main()
{
	Derive d;
	//d的前四个字节是虚表指针,拿到虚表指针之后调用打印虚表函数
	PrintVTable((VFUNC*)(*(int*)&d));
	return 0;
}

发现d的虚表有如下几个虚函数:
在这里插入图片描述
在这里插入图片描述

多继承中的虚函数表
class Base1 
{
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};
class Base2 
{
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2;
};
class Derive : public Base1, public Base2 
{
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1;
};

调用监视窗口进行查看我们发现Derive里的两个func1都被覆盖了,但是Derive里的func3去哪里了呢?
在这里插入图片描述
我们写代码来打印虚函数表,进行验证:(这里需要注意的是,d中的虚函数表有两个,一个是从Base1继承下来的,一个是从Base2继承下来的,编译器会根据继承的顺序进行排列)

typedef void(*VFUNC)();
void PrintVTable(VFUNC* table)
{
	cout << "虚函数表:" << table << endl;
	for (int i = 0; table[i] != nullptr; i++)
	{
		printf("虚函数%d : [0x%p]->", i, table[i]);
		table[i]();
	}
	cout << endl;
}
int main()
{
	Base1 b1;
	Base2 b2;
	Derive d;
	
	//打印d中继承的Base1的虚函数表
	PrintVTable((VFUNC*)(*(int*)&d));
	
	//打印d中继承的Base2的虚函数表
	PrintVTable((VFUNC*)(*(int*)((char*)&d + sizeof(Base1))));
	return 0;
}

这里打印Base1的虚函数表和单继承的原理一样,那么打印Base2的虚函数表就需要谈一谈了:

  1. 将d的地址强转为char*,一次取一个字节
  2. 再加上sizeof(Base1),就是一次加一个字节,加Base1的大小,这里就跳过了Base1
  3. 因为编译器是按照继承的顺序来进行存放的,所以跳过了Base1此时指向的就是Base2的虚函数表的首地址
  4. 拿到首地址之后在强转为int*然后再解引用,取到Base2的前四个字节,这个值就是指向虚表的指针
  5. 再强转成VFUNC*,因为虚表就是一个存VFUNC类型(虚函数指针类型)的数组。
  6. 虚表指针传递给PrintVTable进行打印虚表

打印结果如下:
在这里插入图片描述
我们发现子类中自己的虚函数会保存在第一个继承的类里的虚函数表里。
在这里插入图片描述

菱形继承、菱形虚拟继承

实际中我们不建议设计出菱形继承及菱形虚拟继承,一方面太复杂容易出问题,另一方面这样的模型,访问基类成员有一定得性能损耗。所以菱形继承、菱形虚拟继承我们的虚表我们就不探究啦 |ू・ω・` ),一般我们也不需要研究清楚,因为实际中很少用。

七、多态常见的面试问题来一波

  1. 什么是多态?
  2. 什么是重载、重写(覆盖)、重定义(隐藏)?
  3. 多态的实现原理?
    答:虚函数表
  4. inline函数可以是虚函数吗?
    答:不能,因为inline函数没有地址,无法把地址放到虚函数表中。
  5. 静态成员可以是虚函数吗?
    答:不能,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。
  6. 构造函数可以是虚函数吗?
    答:不能,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。如果是虚函数的话会构成多态,多态是一种运行时编译,所不可以。
  7. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?
    答:可以,并且最好把基类的析构函数定义成虚函数。父类的指针指向一个子类的对象时,释放时就应该去调用子类的析构函数,这是一种多态行为。
  8. 对象访问普通函数快还是虚函数更快?
    答:首先如果是普通对象,是一样快的。如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。
  9. 虚函数表是在什么阶段生成的,存在哪的?
    答:虚函数是在编译阶段就生成的,一般情况下存在代码段的。
  10. 什么是抽象类?抽象类的作用?
    答:抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。
2025红队实战:Win11环境下ZAP、CobaltStrike与免杀套件深度评测 在网络安全领域,渗透测试与红队行动是评估系统防御能力的关键手段。其核心原理在于模拟真实攻击者的技术与流程,以发现潜在的安全漏洞。这项技术的价值在于主动识别风险,提升整体安全防护水平,广泛应用于企业安全评估、漏洞挖掘和攻防演练等场景。随着Windows 11系统普及,其增强的安全机制(如内存完整性、基于虚拟化的安全)对传统攻击工具链提出了新的挑战。本文聚焦于**CobaltStrike二开版**与**免杀套件**在Win11环境下的实战应用与深度对抗,探讨如何优化工具链以应对现代端点检测与响应(EDR)和高级 阅读详情

相关推荐

离线AI实战指南:本地部署大模型处理PDF/Word/Excel

离线AI是指在无网络、不上传数据前提下,于个人设备运行大语言模型并完成文档理解、多轮对话与代码辅助等任务的技术方案。其核心依赖本地模型推理、文档解析向量化和轻量级对话调度三大能力。随着Phi-3、Qwen2、Llama3等轻量化开源模型普及,以及Ollama、LM Studio等易用工具成熟,普通用户已可在主流笔记本上实现PDF摘要、合同比对、代码注释等真实办公场景。本文聚焦离线AI的硬件适配、模型选型、文件处理链路与知识库构建,尤其强调中文OCR支持、结构化文档提取与CPU/GPU混合推理优化,助力非开发

weixin_31968639的博客 495

父类和子类同名函数以及虚函数多态问题

1、子类和父类返回值参数相同,函数名相同,有virtual关键字,则由对象的类型决定调用哪个函数。 2、子类和父类只要函数名相同,没有virtual关键字,则子类的对象没有办法调用到父类的同名函数,父类的同名函数被隐藏了,也可以强制调用父类的同名函数class::funtion_name。 3、子类和父类参数不同,函数名相同,有virtual关键字,则不存在多态性,子类的对象没有办法调用到父类的同名函数,父类的同名函数被隐藏了,也可以强制调用父类的同名函数class::funtion_name。 4、子类和

梅杏柿的博客 6406

Bulk / Smart-seq2数据分析一般流程

Bulk RNA-seq(RNA-Seq of bulk samples)是一种RNA-Seq技术应用,它是通过将整个组织或细胞群体的RNA提取并混合,进行高通量测序来分析基因表达的技术。转录本定量结果可以用于后续的差异表达分析和聚类分析。功能注释和富集分析:对差异表达基因进行功能注释和富集分析,以帮助理解差异表达基因的功能和调控网络,从而获得对研究样品的更深入的理解。数据可视化:最后,将聚类分析的结果进行可视化,可以使用常见的数据可视化工具,如ggplot2、Plotly等,来帮助用户更好地理解数据。

weixin_54519672的博客 5350

C++中的虚函数

多态 多态是面向对象的三大特征之一,其它两大特征分别是 封装 和 继承 所谓 多态,简单来说,就是当发出一条命令时,不同的对象 接收到同样的命令后所做出的动作是不同的 而书本上的定义则是: 其实就是在说两个概念:静态多态和动态多态 静态多态 静态多态,也叫 早绑定 看如下实例: 定义一个矩形类:Rect,其中有两个同名成员函数:calcArea(),显然 二者互为重载(名字相同,参数可辨) 在使用时: 当实例化一个 Rect 的对象后,就可以通过对象分别调用这两个函数, 计算机在编译...

wesigj的博客 1248

蓝桥杯FPGA赛道积分赛

代码如下: 按键驱动 代码如下 按键驱动 代码如下: 顶层文件 按键驱动 数码管驱动 声明:本代码借鉴网络资料,如有侵权和错误请联系作者删除。我是从寒假开始备赛的,由于我基础不行,备赛过程中也是混混呃呃的,备赛效率不高,总体来说备赛不认真,有点拖拉,但是最后我也坚持备赛到了今天,在备赛过程中,即复习了旧的东西,也学到了新的东西,总结起来还是有点收获的,后天北京、天津、河北地区就要进行省赛了,我会全力以赴,不管结果怎么样,尽力就好,最后祝大家都能

weixin_69804913的博客 1991

抖音最新风控体系研究

小编从技术角度对抖音的风控史和落地目标,跟大家聊一聊抖音,包括海外版抖音TikTok的现状与生态。 1、非常非常早的时期,抖音刚出来的时候,没有任何封禁,这个阶段,导入一个开发库,加上一个请求头,咵咵咵的数据随便拿。 2、2018-2019年,抖音加入了设备id和xg机制,在绝大多数的接口中,携带了设备id参数,同时在请求头中加入了xg,如今的apk市场,能追溯到的最早xg是0200打头的,而小编见过的最早的xg是0000打头的。这个时期的接口,这些参数都还只是预设,没有实际的用处,设备随便写,

qq517348412的博客 1万+

C++笔记:父类中声明为虚函数,子类重写后为虚函数

文章目录前言父类中声明为虚函数,子类重写后为虚函数查看汇编代码子类调用父类的成员函数 前言 父类中声明为虚函数,子类重写后为虚函数 代码 #include <iostream> using namespace std; struct Animal { void speak() { cout << "Animal::speak()" << endl; } void run() { cout << "Animal::run()" &lt.

sangba2019的博客 1360

CTFshow-CRYPTO(持续更新)

密码学签到 }wohs.ftc{galf 将字符串逆序即可 letters = '}wohs.ftc{galf' a = list(letters) a.reverse() for letters in a: print(letters,end='') crypto2 打开浏览器的控制台,复制粘贴回车即可得到flag crypto3 这一题同上 crypto4 如图填写即可,一开始e填写的是17,一直回答错误,后来经过群内大佬提醒软件的e是十六进制的,17转十六进制就是0x11 cr

i_kei的博客 1万+

c++ 继承关系中的虚函数表

1. 子类继承父类的虚函数表的方式是复制一份。存在虚函数的类,都有自己的虚函数表,不与其他类共用。 2. 只要祖先类的某个函数被声明位virtual, 则在后代中无论是否显式地添加virtual,该函数一直都是虚的。 3. 如果子类重写了某个虚函数,则该类的虚函数表对应位置上的虚函数地址会被覆盖。如果完全不重写,则子类的虚函数表里面的内容和父类虚函数表内容保持一致。 4. 虚函数表类似于类的静态成员,被该类的所有实例共享。只不过该表是只读的,不存在线程安全问题。 5. 实例对象在起始4字节处,会存放

yuanshenqiang的博客 4410

国科大——形式语言与自动机理论(0812课程)——作业

此次作业题考察,包括但不限于有限自动机、无限自动机、正则文法、正则表达式以及正则语言的性质,题考查下推自动机相关的知识,题考查图灵机相关的知识。此课程建议本科学习过课程的同学选修,成绩占比:考试100%。此课程虽然留有作业,但可做也可不做,且不考勤。

qq_54145399的博客 706

XGBoost特征重要性为0的问题:深度解析与应对策略

在机器学习领域,XGBoost(Extreme Gradient Boosting)作为一款高效且强大的集成学习算法,已经被广泛应用于各类预测任务中。然而,在实际应用过程中,许多数据科学家和工程师们遇到了一个令人困惑的现象——某些特征的重要性值为0。这不仅影响了模型的解释性,还可能导致特征选择过程中的误判。本文将深入探讨这一问题,分析其背后的原因,并提供相应的解决方案。在深入探讨特征重要性为0的问题之前,我们首先需要了解XGBoost是如何计算特征重要性的。XGBoost提供了三种常见的特征重要性计算方法:

cda2024的博客 1705

对c++中函数同名情况的总结

c++中函数同名的情况有三种:重载(overload),覆盖(override)和隐藏。   1.概念上的区别 重载:函数名相同,参数不同。重载函数处于同一个范围,比如同一个类中。   覆盖:函数名和参数都相同。函数处于基类和派生类中。它是针对虚函数的概念,指的是派生类的成员函数对基类成员函数的重新定义。这种关系的函数前面要加关键字virtual(基类中的虚函数必加,

天才在于积累 8628

Python李峋同款跳动的爱心(完整代码)

Python语言实现李峋同款可写字版跳动的爱心的完整代码。

AIGC 4万+

继承与多态实战:CPP-Crash-Course中的高级C++特性

在C++编程中,继承与多态是面向对象编程的核心特性,它们能够显著提升代码的复用性和扩展性。CPP-Crash-Course项目通过清晰的示例代码,展示了如何在实际开发中应用这些高级特性。本文将带你深入理解继承与多态的概念,并通过项目中的实例代码,掌握它们的实际应用技巧。 ## 继承:代码复用的基石 继承允许我们创建新类(派生类)来继承现有类(基类)的属性和方法,从而实现代码的复用和扩展。在CP

gitblog_00025的博客 820

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【C++】:多态的实现

本文介绍了C++多态的概念与实现。多态指不同对象(基类与派生类)通过同一接口产生不同行为,需满足:通过父类指针/引用调用虚函数,且子类完成虚函数重写。文章详细讲解了虚函数定义、重写与重定义的区别,以及析构函数的多态特性。同时介绍了C++11的override和final关键字用法,以及防止类继承的设计方法。最后总结多态是针对成员函数的特性,虚函数继承的是接口使用权而非实现。全文通过具体代码示例阐述了多态的实现机制和使用注意事项。

qq_58135952的博客 1013

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C++:多态 详解

多态的概念:通俗来说,就是多种形态,。举个例子:比如,当买票时,是全价买票;买票时,是半价买票;买票时是优先买票。再举个栗子:最近为了,支付宝年底经常会做诱人的的活动。那么大家想想为什么有人扫的红包又大又新鲜8块、10块...,而有人扫的红包都是1毛,5毛....。其实这背后也是一个多态行为。支付宝首先会分析你的账户数据,比如你是新用户、比如你没有经常支付宝支付等等,那么你需要被鼓励使用支付宝,那么就你扫码金额=;.................................

zhang_si_hang的博客 3万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

C/C++编程:模板的多态

多态是一种能够令单一的泛型标记关联不同特定行为的能力。对于面向对象的程序设计而言,多态是一块基石。在C++中,这块基石主要是通过继承和虚函数实现的。由于这两个机制都是(至少一部分)在运行期进行处理的,因此我们把这种多态称为动多态(一般讲的多态就是这种多态)。然而,模板也允许我们使用单一的泛型标记来关联不同的特定行为,但是这种关联是在编译期进行处理的。因此我们把这种叫做静多态 动多态 动多态是通过继承和虚函数实现的 动多态的设计思想:对于几个相关对象的类型,确定它们之间的一个共同功能集;然后在基类中,把这些

OceanStar的博客 3269

c++学习:多态

因为基类的getResult函数用virtual来修饰,表示虚函数,当继承了基类的派生类创建对象时,就会生成一个虚函数表,函数的地址就会存放在虚函数表里,当我们在派生类重写基类的getResult函数时,c++就会把重写后的函数地址替换掉虚函数表里的基类getResult函数地址,当我们调用的时候就会查到虚函数表的地址,进行调用所对应地址的函数。调用成员函数时,会根据调用函数的对象的类型来执行不同的函数,同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。属于静态多态,编译时多态。

weixin_59669309的博客 482

【c++】: 多态

说明 C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数; 形成多态必须具备三个条件: 1、必须存在继承关系; 2、继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字Virtual声明的函数,在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数); 3、存在基类类型的指针或者引用,通过该指针或引用调用虚函数; 例子 1.在 Shape 类中,area() 的声明前不放置关键字 virtual #include <iostream> using

Jack_Kuo的博客 361

对于C++:多态的解析—上

本文深入解析C++多态特性,重点介绍运行时多态的实现原理。主要内容包括:1)多态的构成条件——必须通过基类指针/引用调用虚函数,且派生类需完成虚函数重写;2)虚函数重写的严格规则("三同"原则)及特殊例外(协变);3)虚析构函数的重要性,避免基类指针释放派生类对象时的内存泄漏;4)C++11新增的override和final关键字,分别用于确保重写有效性和禁止重写。文章通过丰富代码示例和常见面试题(如"B->1"输出问题),剖析多态的实现细节与注意事项

2503_92929084的博客 1735

【C++】一文看懂 C++ 多态:动态与静态多态的全面剖析

多态来源于希腊语,意为“多种形态”。在编程中,多态性指的是在相同的接口下,不同的数据类型可以表现出不同的行为。编译时多态和运行时多态。编译时多态通过函数重载和运算符重载实现,允许在编译阶段确定具体的函数调用。运行时多态通过虚函数和继承实现,允许在运行时根据对象的实际类型确定具体的函数调用。多态性极大地提高了代码的灵活性和可维护性,是面向对象编程中不可或缺的组成部分。

2403_86785171的博客 2070

【C++:多态】深入剖析C++多态精髓:虚函数机制、重写规范与现代C++多态控制

多态是一个继承关系的下的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象优惠买票。2.7。

艾莉丝努力练剑的博客,感谢大家一直以来的对艾莉丝的支持和鼓励,uu们如果对C/C++方向感兴趣的话,可以通过艾莉丝主页的微信名片加艾莉丝的好友,和努力练剑的艾莉丝一起加油! 1465

C++ 静态多态与动态多态详解:从编译时到运行时的多态实现

本文详细介绍了C++中的两种多态实现方式:静态多态和动态多态。静态多态(编译时多态)通过函数重载和模板实现,具有零运行时开销但灵活性有限;动态多态(运行时多态)通过虚函数和继承实现,依赖虚函数表机制,虽然有一定性能开销但支持运行时行为改变。两种多态各有优缺点,静态多态适合性能敏感场景,动态多态适合需要运行时灵活性的场景。文章通过代码示例展示了两种多态的具体实现方式,并分析了它们的特点和适用情况。

本博客分享软硬件一体化开发实战。硬件涵盖 PCB 设计、STM32 等 MCU 底层开发;软件包含 C++、Rust,Qt/QML、PyQt、Slint、TouchGFX、LVGL 各类 GUI 框架。方便软硬件开发者查阅学习。欢迎关注! 678
上一篇: C++:菱形继承及菱形虚拟继承
下一篇: C++:函数重载、重定义与重写
ETalien_
博客等级 码龄8年 154粉丝 199原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值