C++从入门到精通 第九章(继承和多态)【下】

第九章:Java多态理解、多态实现、重写、转型和抽象类 在类等级的不同层次中可以共享一个方法的名字,不同层次中的每个类各自按自己的需要来实现这个行为。比如买票行为,学生和普通人都属于人,但是学生买票可以半价,而普通人是全票。讲到这里,其实已经完成了多态,所以日后我们就可以利用继承和转型来完成。在构造B对象时会调用A的构造方法,在A的构造方法中调用了。向下转型很不安全,而且有时会有严重的歧义。完成某个行为时,不同对象有着不同的完成方法。方法,但此时是B对象,所以会调用到B的。,而B对象而没有完成构造,所以。但是我们可以向下转型,也即。下面的代码中,B继承自A,.. 阅读详情

 写在前面:

  1. 本系列专栏主要介绍C++的相关知识,思路以下面的参考链接教程为主,大部分笔记也出自该教程,笔者的原创部分主要在示例代码的注释部分。
  2. 除了参考下面的链接教程以外,笔者还参考了其它的一些C++教材(比如计算机二级教材和C语言教材),笔者认为重要的部分大多都会用粗体标注(未被标注出的部分可能全是重点,可根据相关部分的示例代码量和注释量判断,或者根据实际经验判断)。
  3. 由于C++基本继承了C语言的所有内容,建议读者先阅读C语言系列的专栏,有一些重点是仅在C语言系列专栏中有介绍的(比如二级指针、预处理等)。
  4. 如有错漏欢迎指出。

参考教程:黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难_哔哩哔哩_bilibili

五、虚函数与多态性

1、多态性的概念

(1)一个面向对象的系统常常要求一组具有相同基本语义的方法能在同一接口下为不同的对象服务,这就是多态性。

(2)在C++中,多态性可分为编译时的多态性(静态多态)和运行时的多态性(动态多态),编译时的多态性是通过函数重载和模板体现的,运行时的多态性是通过虚函数体现的。

(3)静态多态和动态多态的区别:

①静态多态的函数地址早绑定——编译阶段确定函数地址。

②动态多态的函数地址晚绑定——运行阶段确定函数地址。

2、虚函数

(1)在非静态成员函数声明的前面加上virtual修饰符,即把该函数声明为虚函数。

(2)在派生类中可以重写从基类继承下来的虚函数,从而提供该函数的适用于派生类的专门版本,如果不重写虚函数,那么继承下来的虚函数仍然保持其在基类中的定义,即派生类和基类使用同一函数版本。(除少数特殊情况外,在派生类中重写虚函数时,函数名、形参和返回值类型必须保持不变)

(3)虚函数在派生类中被重写后,重写的函数仍然是虚函数,可以在其派生类中再次被重写。对于虚函数的重写函数,无论是否使用virtual修饰符都是虚函数(建议加上,避免遗忘它是虚函数)。

(4)对虚函数的调用有非多态调用和多态调用两种方式:

①非多态调用是指不借助指针或引用的直接调用,它建立在静态绑定机制基础之上,不具备多态特征)。

②多态调用是指借助指向基类的指针或引用的调用,一个基类指针(或引用)可以指向它的派生类对象,而且通过这样的指针(或引用)调用虚函数时,调用的是该指针(或引用)实际所指向的对象所在类的那个重写版本。

(5)基类中的实函数也可以在派生类中改写,但改写的函数仍然是实函数,调用实函数时,通过基类指针(或引用)所调用的也只能是基类的函数版本,无法调用到派生类中的改写函数。(换句话说,对实函数的任何形式的调用都是非多态的)

(6)举例:

①例1:

#include<iostream>
using namespace std;

class Animal
{
public:
	int m_Age;
	/*void speak()
	{
		cout << "动物在说话" << endl;
	}*/
	virtual void speak()          //虚函数
	{
		cout << "动物在说话" << endl;
	}
};
class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};
class Dog :public Animal
{
public:
	void speak()
	{
		cout << "小狗在说话" << endl;
	}
};

//地址早绑定 在编译阶段确定函数地址
//如果想让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段绑定(地址晚绑定)
void doSpeak(Animal &animal)   //Animal & animal = cat/dog;父类的指针或者引用执行与子类对象
{
	animal.speak();   //动态多态满足条件:有继承关系;子类重写父类的虚函数
	//重写时,函数的返回值类型、函数名、参数列表都要完全相同
}

void test01()
{
	Cat cat;
	doSpeak(cat);    
	Dog dog;
	doSpeak(dog);
}

int main() {

	test01();

	system("pause");

	return 0;
}

②例2:

#include<iostream>
using namespace std;

class Animal
{
public:
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};
class Cat :public Animal
{
public:
	/*void speak()
	{
		cout << "小猫在说话" << endl;
	}*/
};
class Dog :public Animal
{
public:
	virtual void speak()
	{
		cout << "小狗在说话" << endl;
	}
};

void doSpeak(Animal &animal)   
{
	animal.speak();   
}

void test01()
{
	Cat cat;
	doSpeak(cat);
	Dog dog;
	doSpeak(dog);
}
void test02()
{
	cout << "sizeof Animal=" << sizeof(Animal) << endl;   //虚函数带指针vfptr,所以对象占4个字节
	cout << "sizeof Animal=" << sizeof(Cat) << endl;
	cout << "sizeof Animal=" << sizeof(Dog) << endl;
}

int main() {

	test01();
	test02();

	system("pause");

	return 0;
}

③例3:

#include<iostream>
using namespace std;
#include<string>

class Calculator         //普通写法
{
public:
	int m_Num1;
	int m_Num2;
	int getResult(string oper)
	{
		if (oper == "+")
		{
			return m_Num1 + m_Num2;
		}
		else if (oper == "-")
		{
			return m_Num1 - m_Num2;
		}
		else if (oper == "*")
		{
			return m_Num1 * m_Num2;
		}
	}
};
class AbstractCalculator    //多态技术
{
public:
	int m_Num1;
	int m_Num2;
	virtual int getResult()
	{
		return 0;
	}
};
class AddCalculator :public AbstractCalculator
{
	int getResult()
	{
		return m_Num1 + m_Num2;
	}
};
class SubCalculator :public AbstractCalculator
{
	int getResult()
	{
		return m_Num1 - m_Num2;
	}
};
class MulCalculator :public AbstractCalculator
{
	int getResult()
	{
		return m_Num1 * m_Num2;
	}
};
//开闭原则:对扩展进行开发,对修改进行关闭
void test01()
{
	Calculator c;
	c.m_Num1 = 10;
	c.m_Num2 = 10;
	cout << c.m_Num1 << "+" << c.m_Num2 << "=" << c.getResult("+") << endl;
	cout << c.m_Num1 << "-" << c.m_Num2 << "=" << c.getResult("-") << endl;
	cout << c.m_Num1 << "*" << c.m_Num2 << "=" << c.getResult("*") << endl;
}
void test02()
{
	AbstractCalculator* abc = new AddCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
	cout << abc->m_Num1 << "+" << abc->m_Num2 << "=" << abc->getResult() << endl;
	delete abc;   //用完计算器后记得销毁
	abc = new SubCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
	cout << abc->m_Num1 << "-" << abc->m_Num2 << "=" << abc->getResult() << endl;
	delete abc;   //用完计算机后记得销毁
	abc = new MulCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
	cout << abc->m_Num1 << "*" << abc->m_Num2 << "=" << abc->getResult() << endl;
}

int main() {

	test01();
	test02();

	system("pause");

	return 0;
}

3、纯虚函数和抽象类

(1)为了将一个虚函数声明为纯虚函数,需要在虚函数原型的语句结束符“;”之前加上“=0”。

(2)拥有纯虚函数的类称为抽象类,抽象类不能用来定义对象。如果一个抽象类的派生类没有重写来自其基类的某个纯虚函数,则该函数在派生类中仍然是纯虚函数,这就使得该派生类也称为抽象类,也就是说,一个派生类可以把重写纯虚函数的任务进一步转交给它自己的派生类。

(3)可以在将一个函数声明为纯虚函数的同时为该函数提供实现版本,一个函数是否为纯虚函数,取决于其原型的尾部是否为“=0;”,与实现版本的有无没有关系。纯虚函数的实现版本通常是不完善的版本,但包含了一些共有操作供各个派生类在重写函数中调用。拥有实现版本的纯虚函数仍然有赖于派生类提供重写版本。

(4)派生类在重写一个纯虚函数时可以继续将之声明为纯虚函数。另外,纯虚函数不得声明为内联函数。

(5)举例:

①例1:

#include<iostream>
using namespace std;

class Base  
{
public:
	int m_Num1;
	int m_Num2;
	virtual int func() = 0;    //纯虚函数
};
class Son :public Base
{
public:
	int func()          //子类必须重写父类中的纯虚函数,否则无法实例化对象
	{
		cout << "func()函数调用" << endl;
	}
};

void test01()
{
	//Base b;      对于抽象类,无法实例化对象,即使是在堆区开辟也不行
	Base * base = new Son;
	base->func();
}

int main() {

	test01();

	system("pause");

	return 0;
}

②例2:

#include<iostream>
using namespace std;

class AbstractDrinking
{
public:
	virtual void zhushui() = 0;
	virtual void chongpao() = 0;
	virtual void daorubeizhong() = 0;
	virtual void jiarufuliao() = 0;
	void makeDrink()
	{
		zhushui();
		chongpao();
		daorubeizhong();
		jiarufuliao();
	}
};
class Coffee :public AbstractDrinking
{
public:
	void zhushui()
	{
		cout << "煮水" << endl;
	}
	virtual void chongpao()         //这里virtual 加不加都行
	{
		cout << "冲泡咖啡" << endl;
	}
	void daorubeizhong()
	{
		cout << "倒入杯中" << endl;
	}
	void jiarufuliao()
	{
		cout << "加糖和牛奶" << endl;
	}
};
class Tea :public AbstractDrinking
{
public:
	void zhushui()          
	{
		cout << "煮水" << endl;
	}
	void chongpao()
	{
		cout << "冲泡茶叶" << endl;
	}
	void daorubeizhong()
	{
		cout << "倒入杯中" << endl;
	}
	void jiarufuliao()
	{
		cout << "加柠檬" << endl;
	}
};
void doWork(AbstractDrinking * abs)
{
	abs->makeDrink() ;
	delete abs;  //做完drink后,释放new在堆区开辟出的数据
}

void test01()
{
	doWork(new Coffee);
	cout << endl;
	doWork(new Tea);
}

int main() {

	test01();

	system("pause");

	return 0;
}

4、虚析构函数和纯虚析构函数

(1)析构函数也可通过virtual修饰而声明为虚函数。

(2)只要虚基类的析构函数声明为虚函数,由它派生的所有派生类的析构函数也一定是虚函数。

(3)在使用多态时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码,为了解决这个问题,需要将父类中的析构函数改为虚析构函数或者纯虚析构函数。

①虚析构函数或纯虚析构函数可达到通过父类指针释放子类对象的目的。

②如果子类中没有堆区数据,可以不将析构函数写为虚析构函数或纯虚析构函数。

③拥有纯虚析构函数(不是虚析构函数)的类也属于抽象类,无法实例化对象。

(4)虚析构函数和纯虚析构函数的语法:

virtual ~<类名>( )     //虚析构函数的定义(类内)

{

        <虚析构函数体>

}

virtual ~<类名>( ) = 0;  //纯虚析构函数的声明(类内)

<类名>::~<类名>( )    //纯虚析构函数的定义(类外)

{

        <纯虚析构函数体>

}

(5)举例:

①例1:

#include<iostream>
using namespace std;
#include<string>

class Animal
{
public:
	virtual void speak() = 0;   //纯虚函数
	Animal()
	{
		cout << "Animal构造函数调用" << endl;
	}
	virtual ~Animal()   //父类指针在析构的时候不会调用子类中的析构函数,子类可能会发生内存泄漏,所以要给它改成虚析构
	{
		cout << "Animal析构函数调用" << endl;
	}
	//virtual ~Animal() = 0;    纯虚析构(需要有声明以及具体实现)
};
/*Animal::~Animal()     
{
    cout << "Animal纯虚析构函数调用" << endl;
}*/
class Cat :public Animal
{
public:
	void speak() 
	{
		cout << *m_Name << "小猫在说话" << endl;
	}
	Cat(string name)
	{
		cout << "Cat构造函数调用" << endl;
		m_Name = new string(name);
	}
	~Cat()
	{
		if (m_Name != NULL)
		{
			cout << "Cat析构函数调用" << endl;
			delete m_Name;
			m_Name = NULL;
		}
	}
	string *m_Name;
};

void test01()
{
	Animal * animal = new Cat("Tom");
	animal->speak();
	delete animal;      
}

int main() {

	test01();

	system("pause");

	return 0;
}

②例2:

#include<iostream>
using namespace std;

class CPU
{
public:
	virtual void calculate() = 0;
};
class VideoCard
{
public:
	virtual void display() = 0;
};
class Memory
{
public:
	virtual void storage() = 0;
};
class Computer
{
public:
	Computer(CPU * cpu, VideoCard * card, Memory * memory)
	{
		m_cpu = cpu;
		m_card = card;
		m_memory = memory;
	}
	void work()
	{
		m_cpu->calculate();
		m_card->display();
		m_memory->storage();
	}
	~Computer()         //提供析构函数释放3个电脑零件
	{
		if (m_cpu != NULL)
		{
			delete m_cpu;
			m_cpu = NULL;
		}
		if (m_card != NULL)
		{
			delete m_card;
			m_card = NULL;
		}
		if (m_memory != NULL)
		{
			delete m_memory;
			m_memory = NULL;
		}
	}
private:
	CPU * m_cpu;
	VideoCard * m_card;
	Memory * m_memory;
};
class IntelCPU :public CPU
{
public:
	void calculate()
	{
		cout << "Inter的CPU开始计算了" << endl;
	}
};
class IntelVideoCard :public VideoCard
{
public:
	void display()
	{
		cout << "Inter的显卡开始显示了" << endl;
	}
};
class IntelMemory :public Memory
{
public:
	void storage()
	{
		cout << "Inter的内存条开始存储了" << endl;
	}
};
class LenovoCPU :public CPU
{
public:
	void calculate()
	{
		cout << "Lenovo的CPU开始计算了" << endl;
	}
};
class LenovoVideoCard :public VideoCard
{
public:
	void display()
	{
		cout << "Lenovo的显卡开始显示了" << endl;
	}
};
class LenovoMemory :public Memory
{
public:
	void storage()
	{
		cout << "Lenovo的内存条开始存储了" << endl;
	}
};

void test01()
{
	//第一台电脑零件
	CPU * intelCPU = new IntelCPU;
	VideoCard * intelCard = new IntelVideoCard;
	Memory * intelMemory = new IntelMemory;
	//第一台电脑
	Computer * c1 = new Computer(intelCPU, intelCard, intelMemory);
	c1->work();
	delete c1;
	cout << endl;
	//第二台电脑
	Computer * c2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);
	c2->work();
	delete c2;
	cout << endl;
	//第三台电脑
	Computer * c3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory);
	c3->work();
	delete c3;
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}
手把手教你用RMII接口配置以太网PHY芯片(附YT8512实战代码) 本文详细介绍了如何使用RMII接口配置以太网PHY芯片,以国产YT8512为例,提供从硬件设计到软件驱动的全流程实战指南。内容包括RMII接口技术解析、YT8512硬件设计要点、驱动开发实战代码及常见问题排查,帮助开发者快速实现以太网通信功能。 阅读详情

相关推荐

kaggle:Digit Recognizer《手写数字识别》你的第一个图像识别竞赛项目

新手,入门,巩固复习,深度学习,图像识别

qq_63591092的博客 3097

C++从入门到精通 第九章(继承和多态)【上】

(1)继承是面向对象三大特性之一,有些类与类之间存在特殊的关系(如下图),定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性,这个时候就可以考虑利用继承的技术,减少重复代码。(2)类的继承是新的类从已有类那里得到已有的特性,从已有的类产生新类的过程就是类的派生。在继承过程中,原有的类或已经存在的用来派生新类的类称为基类或父类,而由已经存在的类派生出的新类则称为派生类或子类。

Zevalin的博客 1179

自动驾驶仿真(五)—— 基于Carsim、Prescan、Simulink的联合仿真

自动驾驶仿真五——基于Carsim、Prescan、Simulink的联合仿真1. 联合仿真流程2. CarSim联合仿真配置要点3. Prescan联合仿真配置要点4. Carsim、Prescan、Simulink联合仿真结果5. 参考学习的书目教材 博主前面的博文已经介绍了Carsim和Prescan各自与Matlab/Simulink的相关联合仿真应用实例,并且论述过几款软件各自的优势及用法,CarSim适合动力学模型的建立,PreScan适合行车场景的搭建,Simulink适合控制算法的设计及信号

zhudj08的博客 1万+

C++-第九章:多态

当子类对父类虚函数进行重写时,子类虚表位置的父类虚函数不变,虚表会新增重写后的虚函数地址,之前已经说到多态的原理是子类继承的父类切片中,虚表指针被替换成了子类的虚表指针,所指向的虚表是新拷贝的虚表,所以只需要子类当中的父类切片就能实现访问子类的虚表了,这就意味着。ptr1虽然类型是父类,但是它指向的是子类,那么按照常理来说应该是半价才对,所以只使用函数重写是不能达到多态的要求的。虚函数不保存在类中,而是在类中形成一个虚表指针,这个指针指向一个虚函数表(简称虚表),虚函数表用于存放虚函数的地址。

2303_78095330的博客 1096

[cadence]Allegro STEP-3D模型导入、匹配、导出的方法及注意事项

如果 Avaliable里面没有和symbols对应的文件,说明没有对应的3D模型,这时候需要在你的step路径下创建y与 .dra 封装文件相同名称的。选择好 Output file 和 name 之后呢,点击 Export。首先打开Setup - Step Package Mapping。注意:路径中不能有中文名称,有的话你会发现不能导出,也不会报错。在路径下将下载或者自己做的 3D模型文件改名之后,重新打开。可在View -> 3D View。

LuDvei的博客 2万+

【微信小程序-uniapp】CustomPicker 自定义单项选择器组件

自定义底部弹出框单项选择器组件,适用于uniapp小程序

Komorebi_00的博客 1531

专业课笔记——(第九章:类的封装、继承、多态)

目录 一、类与结构体 1.类与结构体 2.new与delete 3.类的封装访问属性 二、类的封装 1.构造函数 2.析构函数 3.静态成员 4.友元 5.运算符重载 三、类的继承 1.继承和派生 2.继承中的构造与析构 3.多继承中的二义性 四、类的多态 1.多态 2.函数的重载、重写、和重定义

你相信光吗 1580

解决pd.read_json报错ValueError: Trailing data问题

首先,我们使用open函数打开JSON文件,然后使用json.load函数将JSON文件数据解码为Python对象。在使用Python进行数据处理中,我们经常需要将JSON格式的数据读入到DataFrame中进行处理。而使用pandas库的read_json函数,就可以方便地将JSON数据读入到DataFrame中。但是有时候在读取JSON数据时,会遇到一个非常常见的错误:ValueError: Trailing data。这个错误的解决方案并不难,只需要在read_json中添加一个参数即可。

学习使你进步。 2234

c++重载,继承,多态知识点总结

第八章 1.重载运算符的组成:关键字operator和其后要定义的运算符。也包含返回类型(运算结果的类型)、参数表(提供参与运算的操作数)以及函数体(进行运算,返回运算结果)。 2.运算符函数的参数个数取决于运算符操作数的个数和运算符函数是成员函数还是非成员函数。非成员运算符函数通常成声明为类的友元,以便访问私有数据成员。 3.除重载的函数调用运算符operator()之外,其他运算符函数不能有默...

qq_43627109的博客 412

SAP MD09 事务码中的物料需求追溯详解

物料需求追溯是指在物料需求计划中,追踪特定物料的需求来源和满足方式的过程。它帮助企业确定每个需求(如销售订单、独立需求、预留等)是由哪些供应元素(如库存、生产订单、采购订单等)来满足的。通过这种追溯,企业可以了解需求和供应之间的关系,从而优化生产和采购计划,减少库存积压,提升供应链效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1193

MIKE21 教程 3.2 随空间变化的网格文件制作(.dfsu文件制作) 曼宁值网格文件制作

上一节讲解了如何制作时间序列文件。本节讲解如何制作仅随空间变化的文件。 目录 1 数据准备 1.1 基于地形设置 1.2 基于地形水深设置: 2 数据导入 3 数据导出

Hello Word 3940

类的继承与多态

文章目录前言一、类的继承与派生1.概念2.单继承二、类的派生 前言 此博客主要讲述类的继承与派生的相关内容,视频请参考 MOOC第九章 提示:以下是本篇文章正文内容,下面案例可供参考 一、类的继承与派生 1.概念 继承——子类具有父类的性质,即在已存在的类上建立另一个新的类。(已存在的类叫做基类或父类,新建立的类叫做子类或派生类) 派生——子类拥有父类没有的性质。 派生类的功能 吸收基类成员 改造基类成员 添加新成员 2.单继承 派生类只有一个直接基类 语法格式: class 派生类名 : <

wwl193206126的博客 623

【BUG已解决】pip install 出现 error: Microsoft Visual C++ 14.0 or greater is required 解决方案

方案磁盘占用适用场景推荐指数安装Build Tools3-6GB长期Windows Python开发⭐⭐⭐⭐⭐寻找预编译wheel无额外占用只是想快速装上某个包⭐⭐⭐⭐⭐用conda安装视包而定已经在用conda环境⭐⭐⭐⭐⭐升级到新版本无额外占用库本身有更新的预编译版本⭐⭐⭐⭐使用WSL2需要额外配置Linux子系统频繁遇到Windows编译问题⭐⭐⭐⭐的核心是Windows 缺少本地 C/C++ 编译器,而目标包需要在本机编译。先看是否有捷径。

博客 1万+

C++入门系列:第六章 继承和派生

文章目录1 单一继承2 访问权限和赋值兼容规则2.1 派生的对象可以赋给基类的对象2.2 派生类的对象可以初始化类的引用2.3 派生类的对象地址可以赋给指向基类的指针:3 私有派生4 多重继承4 二义性及其支配规则6 派生类支配基类的同名函数 1 单一继承 在C++中,声明单一继承的一般形式如下: class 派生类名:访问权限 基类名 { private: 成员声明列表 protecte...

Vincent的博客 437

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C++语言第九章 多态

所谓运行时多态,具体点就是去完成某个行为(函数),可以传不同的对象就会完成不同的行为,就达到多种形态。比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是优惠买票(5折或75折);军人买票时是优先买票。

Nightmare1000的博客 807

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

C++ 第九章 继承与派生

本章提要: 1.继承与派生的概念 2.派生类的构造函数与析构函数 3.冲突、支配规则与赋值兼容规则 4.虚基类

weixin_74774974的博客 1267

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C++继承、重载、多态相关问题(简单但通俗易懂)

关系含义is-a真实继承关系is-like-a功能相似但不是继承只有满足 is-a 才应该使用继承子类可以完全替代父类不应该使用继承如果派生类要覆盖基类的成员函数,基类函数必须声明为虚函数,派生类函数的函数名、参数列表必须与基类完全相同,返回类型必须一致或满足协变返回类型,同时访问权限不能比基类更严格。通常建议使用override关键字以保证函数正确覆盖。项目继承组合关系is-ahas-a耦合程度高低是否支持多态支持一般不支持灵活性较低较高。

Chimera_tu的博客 571

C++入门系列:第八章 多态性和虚函数

文章目录1 多态性2 虚函数2.1 虚函数实现多态性的条件2.2 构造函数和析构函数调用虚函数2.3 纯虚函数与抽象类2.4 类成员函数的指针与多态性 1 多态性 派生一个类的原因并非总是为了添加新的数据成员或成员函数,有时是为了重新定义基类的成员函数。 #include <iostream> using namespace std; const double PI = 3.14159...

Vincent的博客 397

C++入门系列:第九章 流类库

文章目录1.1 默认输入输出格式控制1.2 文件流1.2.1 输出流的open函数1.2.2 输入流类的open函数1.2.3 文件流综合示例 把接收输出数据的地方叫做目标,把输入数据来自的地方叫做源。 C++的流类库由几个I/O操作的基础类和几个支持特定种类源和目标的I/O操作的类组成。 这些基础类在头文件 <iostream> 中说明。ios类中的一个指针成员指向streambuf...

Vincent的博客 408

04737自考C++程序设计知识点总结、考点串讲、考前复习

04737自考C++程序设计知识点总结引言第一章 认识C++的对象1.1 初识C++的函数和对象1.2 认识C++语言面向过程编程的特点1.3 程序的编辑、编译和运行的基本概念第二章 从结构到类的演变2.1 结构的演化2.2 从结构演变一个简单的类2.3 面向过程与面向对象2.4 C++面向对象程序设计的特点2.5 使用类和对象2.6 string对象数组与泛型算法更新中~未完待续2020/10/21第三章 函数与函数模板第四章 类与对象第五章 特殊函数和成员第六章 继承和派生第七章 类模板与向量第八章 多

weixin_46287713的博客 1万+

第九章 多重继承

第九章 多重继承 9.1分类化继承 1.多重继承:一个对象可以有两个或更多不同的父类,并可以继承每个父类的数据和行为。 ​ 派生的分类对每个父类仍然符合"是一个"规则或"作为一个"关系。 ​ 同时扮演多个角色 ​ magnitude number char integer complex 3.多重继承中存在的问题 (1)父类存在同名的方法。 例如:CardDeck 中存在函数draw()画一个Card GraphicalObject中存在函数draw()画一个image 那么他们的子类Graph

梦平的博客 554

C++面向对象--第九章类的继承和派生

父类的publicprotectedprivate都占用子类空间。虽然在子类中访问不到父类的private,但是依旧占用位置class Basepublic:int a;int e;

啊艺哥哥的博客 1007

C++最全面复习:从入门到精通(2026年)

本文系统梳理了C++的核心知识体系,涵盖基础语法到现代特性,从面向对象到并发编程。主要内容包括: C++八大核心板块: 基础语法与类型系统(引用、const、auto) 指针与内存管理(智能指针) 面向对象(封装、继承、多态) 模板与泛型编程 STL标准库 现代C++特性(Lambda、移动语义) 多线程与并发 异常处理与RAII 关键语法解析: 引用与指针区别(必须初始化、不可空) const的四种用法(变量、指针、引用、成员函数) auto自动类型推导与decltype类型获取 面向对象核心: 封装(访

我是一颗柠檬的博客 3125

精通 C++ 游戏开发(一)

尽管现在许多语言被用于开发游戏,但 C++仍然是专业开发的标准。绝大多数库、引擎和工具链仍然严格使用 C++开发。以其性能和可靠性而闻名,C++仍然是真正跨平台兼容性的最佳选择。通过阅读本书,您正在开始掌握这种强大语言的旅程。尽管这个旅程会很漫长,但它将充满发现!即使在我花费了无数小时与 C++一起工作之后,我仍然发现自己在发现新技术和方法时充满了喜悦。在本书中,我希望给您提供工具和理解,为您继续学习之旅做好准备。尽管新的、时髦的工具和引擎可能会出现并有可能消失,但对游戏、它们的工具和引擎在低级别上是如何开

龙哥盟 432

C++笔试试题讲解(~~~可能是全站唯独一份有解析的~~~)

C++笔试题前言一、面向对象程序概论基本理论笔试题 前言 笔者整理了C++的笔试题,希望能在理论知识上帮到大家,解析为博主所作,若有问题,请私信博主或在评论区留言 提示:以下是本篇文章正文内容,下面示例可供参考 一、面向对象程序概论 基本理论 1.在结构化程序设计方法中,程序可表示为程序=数据结构+算法; 而面向对象的程序设计方法,程序可表示为程序=对象+消息。 2. 结构化程序设计方法中的基本模块是过程;而面向对象程序设计方法中的基本模块是类。 3. 面向对象程序设计方法具有抽象性、封装性、继承性和

我在人间找bug 7459

C++八九十章知识总结

C++面向对象程序设计这本书的学习已经接近尾声了,在后面的诸多章节中,重点学习了八九十三章。 第八章讲的是运算符重载,C++预定义中的运算符的操作对象只局限于基本的内置数据类型,但是对于我们自定义的类型(类)是没有办法操作的。但是大多时候我们需要对我们定义的类型进行类似的运算,这个时候就需要我们对这么运算符进行重新定义,赋予其新的功能,以满足自身的需求。运算符重载特别实用,我目前最常用的就是重载...

qq_43215434的博客 217
上一篇: C++从入门到精通 第九章(继承和多态)【上】
下一篇: C++从入门到精通 第十章(运算符重载)
Zevalin爱灰灰
Zevalin爱灰灰 优质创作者: 嵌入式与硬件开发技术领域 优质创作者: 嵌入式与硬件开发技术领域
博客等级 码龄3年 7137粉丝 552原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zevalin爱灰灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值