IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++复习日记2 虚函数和多态性 -> 正文阅读

[C++知识库]c++复习日记2 虚函数和多态性

8月17日学习c++虚函数与多态性、模板和流。

“虚函数”、“多态性”和函数的“重载”是密切相关的。普通函数重载,在一个类中可以通过不同的参数特征区分;在派生类中可以重载基类的成员函数(这里正如8.18继承与派生笔记中提到的“派生类与基类有同名函数时,可以屏蔽基类同名函数”)。

重载函数是c++多态性的一种体现形式。虚函数允许函数调用与函数体的联系在运行时才能进行,称为动态联编。静态联编是程序各个模块在程序运行之前进行的关系匹配。调用一个函数,编译期间就能准确获得函数入口和返回的地址以及参数信息等。动态联编是程序运行时进行的,比如for循环的结果直到程序运行进行动态联编时才能得到。

c++动态联编以来虚函数和基类指针实现。如用基类指针引用派生类对象,如下:

#include <iostream>
#include <cstring>
using namespace std;
class student
{
public:
 ? ?char name[10];
 ? ?void putname(char* n)
 ?  {
 ? ? ? ?strcpy_s(name, n);
 ?  }
 ? ?void showname() const
 ?  {
 ? ? ? ?cout << name << endl;
 ?  }
};
class ustb_student :public student
{
public:
 ? ?double number;
 ? ?void putnum(double num)
 ?  {
 ? ? ? ?number = num;
 ?  }
 ? ?void shownum() const
 ?  {
 ? ? ? ?cout << number << endl;
 ?  }
};
int main()
{
 ? ?student* stu1;
 ? ?student stu;
 ? ?ustb_student ustb_stu;
 ? ?stu1 = &stu; ? ?//先令基类指针指向基类对象
 ? ?stu1->putname("zzy");
 ? ?stu1->showname();
 ? ?stu1 = &ustb_stu; ? ?//再令基类指针指向派生类对象
 ? ?stu1->putname("zht");
 ? ?stu1->showname();
 ? ?ustb_stu.putnum(4192);
 ?  ((ustb_student*)stu1)->shownum(); ? //这里等价于(ustb_student)(*stu1).shownum()
}

输出:

zzy zht 4192

上例中,基类指针指向派生类类对象可以对其进行操作,但是不能直接调用派生类自己的成员函数,除非进行强制类型转换。

如果用派生类指针引用基类对象,则必须通过强制类型转换。上面例子中如果将主函数改为:

int main()
{
 ? ?ustb_student* stu1;
 ? ?ustb_student ustb_stu;
 ? ?ustb_stu.putname("zzy");
 ? ?stu1 = &ustb_stu; ? ?//派生类指针指向派生类对象
 ?  ((student *)stu1)->show(); ? ?//派生类对象指针类型转换,调用基类显示函数
 ?  ((student)ustb_stu).show();
 ?  ((student)*stu1).show();
}

输出:

student_name= zzy student_name= zzy

student_name= zzy

最后三句是对象指针类或对象类的类型转换,它们是等价的,很容易分析出来。

下面就要开始虚函数内容了。在昨天的笔记中,我们用到了虚继承来避免DAG图“先分再合”导致的同一函数在其派生类的派生类中的二义性。当时我们还不清楚它的作用原理,在这里我们将把他搞清楚。

上面回顾了基类指针指向派生类对象,后对其进行操作。在这里先提出一个问题:如果派生类中有与基类同名函数,那么利用此种方式调用这个同名函数,会执行在基类定义的版本,还是在派生类中定义的版本?

做个实验就可以看出是基类的版本。其实我觉得,在第一个例子中,指针stu1指向派生类对象ustb_stu后调用putname函数。putname函数仅在基类中定义,所以调用的应当是基类的版本。如果想调用派生类的版本,需要做类型转换,将指针转换为派生类。

那么如何不做指针的类型转换,让stu1->showname()成为一个统一的接口,来调用不通版本的同名函数呢?---答案是把这个同名函数在基类里写为虚函数就好了,前面加上virtual。这样就能实现基类指针指向哪个派生类,就调用那个派生类版本的(同名)函数了。

虚函数重载要求函数名、参数特征、返回类型等等都相同,否则会破坏虚的重载特性。构造函数和友元函数不能声明为虚函数,但是析构函数可以---不仅可以,还有很大的好处,可以使基类指针指向派生类对象进行操作后,删除这个指针,就可以先后执行基类和派生类的虚构函数;否则只会执行派生类的析构函数。

纯虚函数是函数赋值为0的虚函数,在派生类中重写其具体定义。抽象类至少有一个纯虚函数,只能作为基类。

忽然想起了stm32编程中的__weak弱函数:

虽然和上文没什么关系,但名字有点像hhh,弱函数为用户省了许多事,MspInit()屏蔽掉了许多跟单片机型号有关的东西,使用户可以专注于配置自己需要的功能。

今天就到这里。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-18 12:31:35  更:2021-08-18 12:34:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 4:31:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计