C++---虚函数


虚函数介绍

虚函数在类中声明为virtual的函数。

虚函数的形式为:

cpp 复制代码
class 类名
{
    //.......
    virtual 返回值类型 函数名(参数列表);
};

例如,图形类(Shape)的show是虚函数。

cpp 复制代码
#include <iostream>
using namespace std;

class Shape //图形类
{
public:
    virtual void show()const //虚函数
    {
        cout << "我是一个图形" << endl;
    }
};

class Rectangle:public Shape //长方形
{
public:
    void show()const
    {
        cout << "我是一个长方形" << endl;
    }
};

int main()
{
    Shape s;
    Rectangle r;
    s.show();
    r.show();

    //把子类对象复制给父类对象,指针或者引用 
    cout << "把子类对象复制给父类对象,指针或者引用后" << endl; 
    s = r; 
    s.show(); 

    Shape* ps = &r; 
    ps->show(); 

    Shape& rs = r; 
    rs.show(); 

    return 0; 
}

虚函数说明:

(1)非类成员函数不能定义为虚函数。

(2)构造函数不能定义为虚函数,但析构函数可以。

(3)虚函数一般不声明为内联函数,因为对虚函数的调用采用的是动态绑定,而对内联函数采用的是静态绑定,即使虚函数在类体内定义,C++编译器也将它视为非内联函数。

(4)在声明函数时加"virtual",定义函数时不加"virtual"。

(5)当一个函数被声明为虚函数后,其派生类中的同名函数自动成为虚函数,在派生类声明该函数时可以加上 virtual,也可以不加,但习惯加virtual,使程序更加清晰。

(6)如果派生类没有对虚函数覆盖定义,则直接继承基类的虚函数。

有了虚函数动态才能实现动态多态.即传入什么类型的对象就调用它对应的函数。

cpp 复制代码
#include <iostream>
using namespace std;

class Shape //图形类
{
public:
    virtual void show()const //虚函数
    {
        cout << "我是一个图形" << endl;
    }
};

class Rectangle:public Shape //长方形
{
public:
    void show()const
    {
        cout << "我是一个长方形" << endl;
    }
};

class Square :public Shape //正方形
{
public:
    void show()const
    {
        cout << "我是正方形" << endl;
    }
};

void test1(const Shape& s)//引用
{
    s.show();
}

void test2(const Shape* ps)//指针
{
    ps->show();
}

int main()
{
    Shape s;
    Rectangle r;
    Square sq;

    //引用
    test1(s);//传入图形,调用图形的show
    test1(r);//传入长方形,调用长方形的show
    test1(sq);//传入正方形,调用正方形的show
    cout << "--------------" << endl;//分割线
    //指针
    test2(&s);//传入图形,调用图形的show
    test2(&r);//传入长方形,调用长方形的show
    test2(&sq);//传入正方形,调用正方形的show

    return 0;
}

总结:

动态多态满足条件

有继承关系

子类覆盖(override)父类中的虚函数

动态多态使用条件

父类指针或父类引用(更常用)指向子类对象

函数覆盖(override):在派生类中重新定义基类虚函数。要求返回值类型,函数名,参数列表与基类的虚函数相同。同名隐藏针对的是非虚函数.

C++11中的final和override说明符

派生类如果定义了一个函数与基类中虚函数的名字相同但是形参不同,这是合法的,编译器将认为新定义的这个函数与基类中原有的函数是相互独立的。这时,派生类的函数并没有覆盖掉基类中的函数。就实际的编程习惯而言,这往往意味着发生了错误,因为我们可能原本希望派生类能覆盖掉基类中的虚函数,但是一不小心把参数列表写错了。

要想调试并发现这样的错误显然非常困难。在 C++11 新标准中我们可以使用override 关键字来说明派生类中的虚函数。这么做的好处是使程序员的意图更加清晰的同时让编译器可以为我们发现一些错误,这在编程实践中显得非常重要。如果我们使用 override 标记了某个函数,但该函数并没有覆盖已存在的虚函数,此时编译器将报错。

override:覆盖,它显式的告诉编译器,当前函数一定是覆盖基类中的虚函数.

cpp 复制代码
class A
{
public:
	virtual void f1(int) const;
	virtual void f2();
	void f3();
};

class B:public A
{
public:
	void f1(int)const override; //正确,f1与基类中的f1匹配
	void f2(int) override;      //错误,A中的f2()和这个不一样
	void f3() override;         //错误,f3不是虚函数
	void f4() override;         //错误,A中没有f4函数
};

final:最终的,这个函数不允许再被子类覆盖

把函数定义成 final,则之后任何试图覆盖该函数的操作都是错误的。

cpp 复制代码
class A
{
public:
    virtual void f1(int) const;
};

class B:public A
{
public:
    void f1(int)const  final; //最终的,不允许后续的子类覆盖f1(int)
};

class C :public B
{
public:
    void f1(int) const;//错误,B中已经将f1(int)声明为final
};

重点名称对比
函数重载:同一个函数名,不同的参数列表(参数个数或类型不同),构成函数重载
同名隐藏:在类继承中对于普通函数子类实现了和父类相同的函数(同名,同参数,同返回值)
函数覆盖:也称同名覆盖,在类继承中对于虚函数子类实现了和父类相同的函数(同名,同参数,同返回值)


本篇完!

相关推荐
Dream it possible!10 分钟前
LeetCode 热题 100_寻找重复数(100_287_中等_C++)(技巧)(暴力解法;哈希集合;二分查找)
c++·leetcode·哈希算法
运维-大白同学37 分钟前
go-数据库基本操作
开发语言·数据库·golang
动感光博1 小时前
Unity(URP渲染管线)的后处理、动画制作、虚拟相机(Virtual Camera)
开发语言·人工智能·计算机视觉·unity·c#·游戏引擎
丶Darling.1 小时前
Day119 | 灵神 | 二叉树 | 二叉树的最近共公共祖先
数据结构·c++·算法·二叉树
蚰蜒螟2 小时前
深入解析JVM字节码解释器执行流程(OpenJDK 17源码实现)
开发语言·jvm·python
keke102 小时前
Java【14_2】接口(Comparable和Comparator)、内部类
java·开发语言
思茂信息2 小时前
CST软件对OPERA&CST软件联合仿真汽车无线充电站对人体的影响
c语言·开发语言·人工智能·matlab·汽车·软件构建
CN.LG2 小时前
Java 乘号来重复字符串的功能
java·开发语言
川川菜鸟2 小时前
2025长三角数学建模C题完整思路
c语言·开发语言·数学建模
萌新下岸多多关照2 小时前
Java中synchronized 关键字
java·开发语言