[C++]详细解释虚函数到底是什么, 有啥用

本篇主要试图解释这些疑问: 虚函数是什么, 为什么要用, 有什么好处?

侯捷老师讲虚函数视频(需要能访问油管)

理解虚函数

  1. 在语法上, 成员函数之前加virtual关键字就让这个函数变成虚函数
  2. 函数的继承不应该从内存角度理解, 而是继承调用权(子类可以调用父类函数), OOP的继承特性需要搭配虚函数才能最大化体现继承的优势.
  3. 成员函数从这个角度可以分成三种:
    a. non-virtual(非虚函数,普通函数)
    b. virtual(虚函数), 希望子类重新定义(override), 且自己对它有默认定义
    c. pure virutal(纯虚函数), 希望子类一定要重新定义, 且自己对它没有默认定义(其实可以有), 后面加const = 0;
virual  void draw() const = 0;
  1. 为什么要把某些函数设成虚函数?
    父类在定义函数时决定暂缓具体实现步骤, 因为子类在设计时有更具体的,精细的想法, 我作为父类的设计者允许子类去override, 通过把自己的函数设置成虚函数, 子类才有机会(权限)去重新定义.

  2. 经典例子:
    使用word/excel/ppt 软件打开文件时, 先弹出文件浏览框,选好文件之后点OK, 程序是这么处理的:
    a. 检查文件名称
    b. 查找文件是否存在
    c. 打开文件
    d. 读出来

这一系列步骤给任何设计师写都差不多, 能不能有人把它写好呢, 因为除了最后一步(读文件), 其他步骤都是一样的, 完全可以事先写好.
于是就有人去写了这个公共的部分, 父类叫CDocument, 里面有个OnFileOpen函数
在这里插入图片描述

//Application Framework
class CDocument
{
public:
	void OnFileOpen()
	{
		...
		Serialize();
		...
	}
	virtual void Serialize() {};
};

父类CDocument的设计者需要写打开文件这个函数时, 因为不知道使用者具体打开哪一种文件(可能是excel, word, ppt等), 就把这个需要具体细节的部分写成一个函数-Serialize, 并把它定义成虚函数, 然后内容空着.
之后, 我们要为word写程序时, 就在word类里把Serialize这个函数补全,

class CMyDoc: public CDocument
{
	virtual void Serialize() {...}
};

用的时候实例化子类的object, 调用父类OnFileOpen()方法(OOP里非常常见). 然后在里面遇到了Serialize这个虚函数, 调用了自己实现的Serialize方法.

main()
{
	CMyDoc myDoc;
	...
	myDoc.OnFileOpen();
}

整个调用顺序遵循下图箭头.
在这里插入图片描述
在设计父类的函数(方法)时, 设计了一些动作, 把其中的一个关键部分延缓, 延缓到子类去决定, 我们就把这个函数的做法叫做Template Method(23个Design Pattern 之一).
这个实现一般动作的设计就叫框架(framework), 其中用到了大量Template Method.

有个关键细节问题: 在运行父类里的OnFileOpen时调用了Serialize, 程序是怎么知道要去CMyDoc里去找这个子类的Serialize方法呢?
其实object调用父类方法时:

myDoc.OnFileOpen();
//在编译器眼中长这样
CDocument::OnFileOpen(&myDoc);

调用的那个object的地址会传进来, 变成this, this所指的就是这个myDoc对象, 到Serialize()的时候, 编译器是看成这样的:

this->Serialize();

虚函数表和虚函数指针的概念之后再谈.

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值