C++:线上课程2_12(多态和虚函数)

news2024/11/27 15:31:28

文章目录

  • 一、多态
    • 1.多态定义
    • 2.多态分类
      • 2.1编译时的多态
      • 2.2运行时的多态
  • 二、虚函数
    • 1.定义
    • 2.成员函数与虚函数
    • 3.为什么构造函数(移动构造函数,拷贝构造函数)不可以定义为虚函数?
    • 4.示例
    • 5.对象和指针和引用调用
    • 6.虚表分配
    • 7.this指针调动示例
    • 8.虚函数调用关系示例


一、多态

1.多态定义

多态性是面向对象程序设计的关键技术之一。若程序设计语言不支持多态性,不能称为面向对象的语言。利用多态性技术,可以调用同一个函数名的函数,实现完全不同的功能。

2.多态分类

2.1编译时的多态

(早期绑定)名字粉碎技术实现

通过函数的重载和运算符的重载来实现的
示例:

int Max(int a, int b)
{
	return a > b ? a : b;
}
char Max(char a, char b)
{
	return a > b ? a : b;
}
int main()
{
	int x = Max(12, 23);
	char ch = Max('c', 'b');
	double dx = Max(12.23, 34.45);
	return 0;
}

2.2运行时的多态

(晚期绑定)虚函数
运行时的多态性是指在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。它是通过类继承关系public和虚函数来实现的。目的也是建立一种通用的程序。通用性是程序追求的主要目标之一。
① 公有继承
② 必须有virtual关键字
③ 引用或者指针返回

示例:

#include<iostream>
#include<list>
#include<type_traits>
#include<initializer_list>
#include<string>
using namespace std;
class Animal
{
private:
    string name;
public:
    Animal(const string& na) :name(na) {}
public:
    virtual void eat() {}
    virtual void walk() {}
    virtual void tail() {}
    virtual void PrintInfo() {}

    string& get_name() { return name; }
    const string& get_name() const { return name; }
};
class Dog :public Animal
{
private:
    string owner;
public:
    Dog(const string& ow, const string na) :Animal(na), owner(ow) {}
    virtual void eat()
    {
        cout << "Dog Eat:bone" << endl;
    }
    virtual void walk()
    {
        cout << "Dog Walk:run" << endl;
    }
    virtual void tail()
    {
        cout << "Dog Tail:wang wang" << endl;
    }
    virtual void PrintInfo()
    {
        cout << "Dog owner: " << owner << endl;
        cout << "Dog name: " << get_name() << endl;
    }
};
class Cat :public Animal
{
private:
    string owner;
public:
    Cat(const string& ow, const string na) :Animal(na), owner(ow) {}
    virtual void eat()
    {
        cout << "Dog Eat:fish" << endl;
    }
    virtual void walk()
    {
        cout << "Dog Walk:silent" << endl;
    }
    virtual void tail()
    {
        cout << "Dog Tail:miao miao" << endl;
    }
    virtual void PrintInfo()
    {
        cout << "Dog owner: " << owner << endl;
        cout << "Dog name: " << get_name() << endl;
    }
};
void fun(Animal& animal)
{
    animal.eat();
    animal.walk();
    animal.tail();
    animal.PrintInfo();
}
int main()
{
    Dog dog("yhping", "hashiqi");
    Cat cat("hm", "Persian");

    fun(dog);
    fun(cat);
    return 0;
}

在这里插入图片描述

二、虚函数

1.定义

虚函数是一个类的成员函数:
virtual 返回类型 函数名 (参数表)

关键字virtual 指明该成员函数为虚函数。virtual 仅用于类定义中,如虚函数在类外定义,可不加virtual。
当一个类的成员函数被定义为虚函数,则由该类派生出来的所有派生类中,该函数始终保持虚函数的特性。

2.成员函数与虚函数

成员函数应尽可能地设置为虚函数,但必须注意以下几条:
(1)派生类中定义虚函数必须与基类中的虚函数同名外,还必须同参数表,同返回类型。否则被认为是重载,而不是虚函数。

class Object
{
public:
    virtual void fun(){}
};
class Base :public Object
{
public:
    virtual void fun(int x) {}
};

如基类中返回基类指针,派生类中返回派生类指针是允许的,这是一个例外。

class Object
{
public:
    virtual Object* fun() {}
};
class Base :public Object
{
public:
    virtual Base* fun(int x) {}
};

(2)只有类的成员函数才能说明为虚函数。这是因为虚函数仅适用于有继承关系的类对象
(3)静态成员函数,是所有同一类对象共有,不受限于某个对象,不能作为虚函数。
(4)实现动态多态性时,必须使用基类类型的指针变量或引用,使该指针指向该基类的不同派生类的对象,并通过该指针指向虚函数,才能实现动态的多态性。
(5)内联函数每个对象一个拷贝,无映射关系,不能作为虚函数。
(6)析构函数可定义为虚函数,构造函数不能定义虚函数,因为在调用构造函数时对象还没有完成实例化。在基类中及其派生类中都动态分配的内存空间时,必须把析构函数定义为虚函数,实现撤消对象时的多态性。
(7)函数执行速度要稍慢一些。为了实现多态性,每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现。所以多态性总是要付出一定代价,但通用性是一个更高的目标。
(8)如果定义放在类外itual 只能加在函数声明前面,不能(再)加在函数定义前面。正确的定义必须不包括virtual。

3.为什么构造函数(移动构造函数,拷贝构造函数)不可以定义为虚函数?

因为在构建虚表之前要先查询构造函数,如果构造函数未定义,那么虚函数就不可以继续。

4.示例

#include<iostream>
#include<list>
#include<type_traits>
#include<initializer_list>
#include<string>
using namespace std;
class Object
{
private:
    int value;
public:
    Object(int x = 0) :value(x) {}
    virtual void add()
    {
        cout << "Object::add" << endl;
    }
    virtual void fun()
    {
        cout << "Obect::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Object::print" << endl;
    }
};
class Base :public Object
{
private:
    int sum;
public:
    Base(int x = 0) :Object(x + 10),sum(x) 
    {

    }
    virtual void add()
    {
        cout << "Base::add" << endl;
    }
    virtual void fun()
    {
        cout << "Base::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Base::print" << endl;
    }
};
int main()
{
    Base base(10);
    Object* op = &base;

    return 0;
}

在这里插入图片描述

5.对象和指针和引用调用

class Object
{
private:
    int value;
public:
    Object(int x = 0) :value(x) {}
    virtual void add()
    {
        cout << "Object::add" << endl;
    }
    virtual void fun()
    {
        cout << "Obect::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Object::print" << endl;
    }
};
class Base :public Object
{
private:
    int sum;
public:
    Base(int x = 0) :Object(x + 10),sum(x) 
    {

    }
    virtual void add()
    {
        cout << "Base::add" << endl;
    }
    virtual void fun()
    {
        cout << "Base::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Base::print" << endl;
    }
};
int main()
{
    Base base(10);
    Object* op = &base;
    Object obj(0);

    //如果用指针或者引用调动虚方法,采取动态编联的方法(在运行时候确定调用关系)
    op = &base;
    op->add();
    op->fun();
    op->print();

    //如果用对象调动虚方法,采取静态编联的方法(编译时期确定对象和方法进行结合)
    obj = base;
    obj.add();
    obj.fun();
    obj.print();

    return 0;
}

6.虚表分配

编译时期加载虚表

#include<iostream>
#include<list>
#include<type_traits>
#include<initializer_list>
#include<string>
using namespace std;
class Object
{
private:
    int value;
public:
    Object(int x = 0) :value(x) {}
    virtual void add()
    {
        cout << "Object::add" << endl;
    }
    virtual void fun()
    {
        cout << "Obect::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Object::print" << endl;
    }
};
class Base :public Object
{
private:
    int sum;
public:
    Base(int x = 0) :Object(x + 10),sum(x) {}
    virtual void add()
    {
        cout << "Base::add" << endl;
    }
    virtual void fun()
    {
        cout << "Base::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Base::show" << endl;
    }
};
class Test :public Base
{
private:
    int num;
public:
    Test(int x=0) :Base(x+10) {}
    virtual void add()
    {
        cout << "Tset::add" << endl;
    }
    virtual void print() const
    {
        cout << "Test::print" << endl;
    }
    virtual void show()
    {
        cout << "Test::show" << endl;
    }
};

7.this指针调动示例

class Object
{
private:
    int value;
public:
    Object(int x = 0) :value(x) {}
    virtual void add()
    {
        cout << "Object::add" << endl;
    }
    virtual void fun()
    {
        cout << "Obect::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Object::print" << endl;
    }
    void fn_a()
    {
        fun();//系统默认为this指针调动
    }
};
class Base :public Object
{
private:
    int sum;
public:
    Base(int x = 0) :Object(x + 10),sum(x) {}
    virtual void add()
    {
        cout << "Base::add" << endl;
    }
    virtual void fun()
    {
        cout << "Base::fun" << endl;
    }
    virtual void print() const
    {
        cout << "Base::show" << endl;
    }
};
class Test :public Base
{
private:
    int num;
public:
    Test(int x=0) :Base(x+10) {}
    virtual void add()
    {
        cout << "Tset::add" << endl;
    }
    virtual void print() const
    {
        cout << "Test::print" << endl;
    }
    virtual void show()
    {
        cout << "Test::show" << endl;
    }
};
int main()
{
    Test t1;
    Base base;
    Object obj;

    t1.fn_a();
    base.fn_a();
    obj.fn_a();
    return 0;
}

8.虚函数调用关系示例

const  float pi = 3.14;

typedef struct _Ops
{
	float (*area)(void*);
}Ops;

typedef struct _Shape
{
	Ops ops;
}Shape;

typedef struct _Square
{
	Shape shape;
	float length;
}Square;

typedef struct _Circle
{
	Shape shape;
	float radius;
}Circle;

float square_area(void* thiz)
{
	if (thiz == NULL) return -1;
	printf("Square area: \n");
	Square* sp = (Square*)thiz;
	float area = sp->length * sp->length;
	return area;
}

float circle_area(void* thiz)
{
	if (thiz == NULL) return -1;
	printf("Circle area: \n");
	Circle* sp = (Circle*)thiz;
	float area = sp->radius * sp->radius * pi;
	return area;
}

int main()
{
	Square square;
	memset(&square, 0, sizeof(Square));
	square.length = 10;
	square.shape.ops.area = square_area;

	Circle circle;
	memset(&circle, 0, sizeof(Circle));
	circle.radius = 10;
	circle.shape.ops.area = circle_area;

	Shape* shape = NULL;
	shape = (Shape*)&square;
	cout << shape->ops.area(&square) << endl;


	shape = (Shape*)&circle;
	cout << shape->ops.area(&circle) << endl;
	return 0;
}

运行结果:
在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1042285.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis7】--6.集群

文章目录 集群1.基本介绍2.redis集群槽位3.redis集群分片4.redis槽位映射5.redis集群环境搭建5.1三主三从redis集群配置5.2启动六台redis实例5.3构建主从关系 6.redis集群读写7.redis集群主从切换8.redis集群扩容9.redis集群缩容10.集群常用操作命令和CRC16算法分析 集群 1.基…

聊聊复杂网络环境下hdfs的BlockMissingException异常|参数dfs.client.use.datanode.hostname

聊聊复杂网络环境下hdfs的BlockMissingException异常|参数dfs.client.use.datanode.hostname 1 从一个复杂网络环境下的 hdfs 报错问题聊起 大家知道&#xff0c;企业真实的网络环境是复杂多变的&#xff0c;这可能有多种原因&#xff1a; 一方面&#xff0c;单台服务器可以…

国产32位单片机 普冉PY32F002B 适用于LED灯驱,控制器等

PY32F002B 系列单片机采用高性能的 32 位 ARM Cortex-M0内核&#xff0c;宽电压工作范围的 MCU。嵌入了24Kbytes Flash 和 3Kbytes SRAM 存储器&#xff0c;最高工作频率 24MHz。有TSSOP20, QFN20, SOP16, SOP14,MSOP10多种不同封装类型多款产品。 芯片集成了I2C、SPI、USART 等…

C#程序中很多ntdll.dll、clr.dll的线程

VS中调试缓慢&#xff0c;如下图 需要“右键工程——调试——取消勾选‘启用本地代码调试’”即可。

划片机是用于半导体芯片和其它电子元件切割的设备

划片机是用于半导体芯片和其它电子元件切割的设备。在电子行业中&#xff0c;划片机广泛应用于半导体器件、LED芯片、功率器件等多个领域。通过划片机&#xff0c;可以将芯片或其它电子元件从其母片或衬底上切割下来&#xff0c;以便进一步的使用和加工。 半导体芯片是现代电子…

瑞芯微RK3568|SDK开发之环境安装及编译操作

1. SDK简介 一个通用 Linux SDK 工程目录包含有buildroot、app、kernel、device、docs、external 等目录。其中一些特性芯片如RK3308/RV1108/RV1109/RV1126等&#xff0c;会有所不同。 ● app&#xff1a;存放上层应用 app&#xff0c;主要是 qcamera/qfm/qplayer/settings 等…

Docker 安装MYSQL 5.7.38

首先创建临时容器 docker run -d -p 3318:3306 --name mysql -e MYSQL_ROOT_PASSWORD123456 mysql:5.7.38创建mysql文件挂载目录&#xff0c;然后从临时容器中拷贝出配置文件 mkdir -p /data/docker/mysql/log mkdir -p /data/docker/mysql/data mkdir -p /data/docker/mysql…

人力资源行业HR从业现状,这份报告了解下

人力资源(Human Resource &#xff0c;简称HR)指在一个国家或地区中&#xff0c;处于劳动年龄、未到劳动年龄和超过劳动年龄但具有劳动能力的人口之和。或者表述为&#xff1a;一个国家或地区的总人口中减去丧失劳动能力的人口之后的人口。人力资源也指一定时期内组织中的人所拥…

2023年信创云管平台选哪家?咨询电话多少?

随着云计算和信创国产化的快速发展&#xff0c;越来越多企业需要支持信创系统的云管平台。但很多企业不知道市面上信创云管平台有哪些&#xff0c;也不知道选哪家&#xff1f;这里我们小编就给大家来回答一下。 2023年信创云管平台选哪家&#xff1f;咨询电话多少&#xff1f;…

Python第二次作业(4)【矩形面积与周长】

作业要求&#xff1a;求任意矩形的面积与周长 代码如下&#xff1a; len int(input("请输入矩形的长:")) wid int(input("请输入矩形的宽:")) area len * wid per (len wid) * 2 print("矩形面积&#xff1a;",area) print("矩形周长…

【Linux】socket网络编程

文章目录 1. 网络进程的端口号2. 认识UDP和TCP3. 网络字节序4. socket通信5. UDP服务器和客户端5.1 基础UDP服务器和客户端5.2 群聊服务器和客户端 6. TCP服务器和客户端6.1 TcpServer6.2 TcpClient6.3 TcpServer的优化引入线程池日志系统服务器守护进程化 1. 网络进程的端口号…

Unity Game FrameWork—框架学习—ab打包流程解析

UGF资源更新与管理 https://www.jianshu.com/p/80bff8c9004a 打包配置 ResourceBuilder.xml文件保存了打包配置信息 参数&#xff1a; InternalResourceVersion&#xff1a;内部版本号 Platforms&#xff1a;生成的ab资源所对应平台编号&#xff0c;二进制左移&#xff0c;与…

中睿天下受邀参加2023北京数字交通大会暨博览会并发表主题演讲

2023年9月11号由中国交通报社、中国交通运输协会联合主办的2023北京数字交通大会暨博览会&#xff08;简称大会暨博览会&#xff09;在北京中国国际展览中心&#xff08;新馆&#xff09;举行。这次大会主题是“数字新时代、交通新未来”&#xff0c;将聚焦数字交通创新发展&am…

国货拟人AI绘图;500+AI岗位合辑;百川x亚马逊AI黑客松;企业级AI行业图谱;100+LLM面试题与答案 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f525; 上万人涌入抖音国货直播间&#xff0c;朴实「商战」带火国民品牌 谁能想到&#xff0c;李佳琦「华西子事件」意外带火了一众国货品牌的…

C#源码 LIS实验室(检验科)信息系统源码 SaaS模式的Client/Server架构

LIS实验室&#xff08;检验科&#xff09;信息系统&#xff0c;一体化设计&#xff0c;与其他系统无缝连接&#xff0c;全程化条码管理。集申请、采样、核收、计费、检验、审核、发布、质控、查询、耗材控制等检验科工作为一体的网络管理系统。 技术细节&#xff1a; 体系结构…

什么是RPA机器人流程自动化软件?

泽众RPA机器人流程自动化软件&#xff0c;是一种能够模拟人类来执行重复性任务的软件&#xff1b;它通过驱动对于系统业务进行统筹安排、协调处理、自动执行以此提升业务处理效率。借助RPA用户可以提高工作效率、节省成本、降低出錯率、节省时间、并从重复性的后台任务中解放劳…

《学术小白学习之路12》进阶-基于Python实现中文文本的DTM主题动态模型构建

《学术小白学习之路》基于Python实现中文文本的DTM主题动态模型构建 一、数据选择二、数据预处理三、输入数据ID映射词典构建四、文档加载成构造语料库五、DTM模型构建与结果分析六、结果进行保存七、保存模型一、数据选择 所选取的数据集是论文摘要,作为实验数据集,共计12条…

中国人民大学与加拿大女王大学金融硕士为何占据在职读研人的心?一起来看看

说起北京地区的中外合作办学在职硕士项目哪个最受欢迎呢&#xff1f;无疑是中国人民大学与加拿大女王大学金融硕士项目&#xff0c;它已经深深占据在职读研人的心。项目历经十年的风雨&#xff0c;有口皆碑。一起去人大女王金融硕士项目为什么这么受青睐。 一、名校光环 女王金…

基于微信小程序的校园代送跑腿系统(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

Python和Scrapy构建可扩展的框架

构建一个可扩展的网络爬虫框架是利用Python和Scrapy实现高效数据采集的重要技能。在本文中&#xff0c;我将为您介绍如何使用Python和Scrapy搭建一个强大灵活的网络爬虫框架。我们将按照以下步骤展开&#xff1a; 1. 安装Scrapy&#xff1a; 首先&#xff0c;确保您已经安装了…