0
点赞
收藏
分享

微信扫一扫

C++学习笔记:虚函数、子类父类的注意事项【Cherno】

_铁马冰河_ 2022-04-16 阅读 67
C++虚函数

先来放几个问题:

为什么要有虚函数,虚函数是什么,怎么定义虚函数,虚函数是怎么起作用的。

让我们跟着这几个问题来捋一捋;

我们定义fa为父类,son为子类

(1)为什么要有虚函数:

所有C++概念都是来解决问题的,虚函数也不例外,当我们定义一个常规函数A,这个函数的形参是fa类,因为son是fa的超集,所以我们可以向A中传递son。这很合理,但是会出现一种情况,如果fa类和son类中有相同的函数B【函数特征标相同】,那么就会调用fa中的B,但是如果我们传son到A中,是想调用A中的B,但很抱歉,因为传递的虽然是son,但是类型却是fa,所以指定的还是fa中的B,那么这个时候虚函数就起到作用了;

【一定要注意,形参的类型要是指针类型或者引用类型,要不然会强制类型转换,如果强制类型转换,那么形参本质就是fa类型了,那这样的话也就没虚函数什么事了】

(2)虚函数是什么:

根据上面的问题,我们大概知道虚函数是什么了,即拥有优先级的函数,我们在fa中声明B为虚函数,就像对系统说,嘿,这个函数的优先级低,如果调用这个类的子类的同名函数,那么就优先调用子类的同名函数。

本菜理解这个优先级为,如果指针的类型是父类,但指针指向的是子类,那么给指针类型指向的父类virtual声明,就是向系统说:“嘿,不要用父类的同名函数,要用指针指向的子类的同名函数”;

(3)怎么定义虚函数:

这个其实很简单,我们只需要在函数的返回类型声明前加上virtual关键字即可:

class g_fa {
public:

	virtual void GetName() { std::cout << "grandfather" << std::endl; }

};

但是,如果我们最好将非虚函数用override标记一下,这样可以增加可读性;

(4)虚函数是怎么起到作用的:

我们定义3个类,g_fa、fa、son类,其中g_fa是fa的父类,fa是son的父类:

#include<iostream>
#include<cstring>
#include"head.h"
#include<string>

class g_fa {
public:

	 void GetName() { std::cout << "grandfather" << std::endl; }

};

class fa:public g_fa {

public:

	void GetName() { std::cout << "father" << std::endl; }
};

class son :public fa{

public:

	void GetName() { std::cout << "son" << std::endl; }

};

void GetName(g_fa &mid) {
	mid.GetName();
}

int main() {

	g_fa g_fa;
	fa fa;
	son son;

	g_fa.GetName();
	son.GetName();
	father.GetName();

}

运行结果很正常:

 但是如果我们调用常规GetName函数:

 这看起来也很合理因为函数的形参是g_fa,但是要知道,因为是引用类型,引用类型的本质是const 指针,而指针是不会类型转换的,顶多我们知道这个这种指向的变量是什么类型,所以我们传递son过去,mid还是一个指向son类的指针。

我们想调用son类中的GetName函数怎么办?

我们可以将g_fa类中的GetName函数标记为虚函数,即最终代码为:

#include<iostream>
#include<cstring>
#include"head.h"
#include<string>

class g_fa {
public:

	 virtual void GetName() { std::cout << "grandfather" << std::endl; }

};

class fa:public g_fa {

public:

	void GetName() { std::cout << "father" << std::endl; }
};

class son :public fa{

public:

	void GetName() { std::cout << "son" << std::endl; }

};

void GetName(g_fa &mid) {
	mid.GetName();
}

int main() {

	g_fa g_fa;
	fa fa;
	son son;

	GetName(g_fa);
	GetName(fa);
	GetName(son);

}

运行结果为:

 这说明,不在调用g_fa中的GetName函数;

有趣的是,如果我们将fa中的GetName函数virtual声明,那么我们得到的依然是同样的结果;

正验证了本菜上面那段话“嘿,不要用父类的同名函数,要用指针指向的子类的同名函数”;

这就是虚函数的作用;

举报

相关推荐

0 条评论