【C++】虚函数

news/2024/7/5 11:12:17

虚函数是构成C++多态的重要一步,今天来说一下虚函数!

虚函数:

在基类(或父类)中,使用virtual关键字对函数进行声明为并在一个或多个派生类(子类)中被重新定义的成员函数,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。

它的用法是这样的virtual + 函数返回类型 + 函数名 +(参数表) {函数体}

首先我们要知道为什么要有虚函数这个东西?

我来看下下面这两段代码的结果再来说结果:

class A
{
public:void fun(){cout << "class A" << endl;}
};class B : public A
{
public:void fun(){cout << "class B" << endl;}
};int main()
{A* p = new B;p->fun();return 0;
}

上述代码很简单,A* p = new B;创建B对象,拿A类型指针指向它,最后运行时,输出的是

但是我明明创建的是B对象啊,为什么会运行class A中的fun函数呢?来看下面代码演示:

class A
{
public:virtual void fun(){cout << "class A" << endl;}
};class B :public A
{
public:virtual void fun(){cout << "class B" << endl;}
};int main()
{A* p = new B;p->fun();return 0;
}

和上述代码的唯一区别就是在父类A中和派生类中的fun函数中加了virtual,声明为虚函数

,运行结果是:

这个运行结果就达到了我们的预期结果,但是为什么加上virtual声明之后运行结果就不同了呢?

 虚函数的原理:

class A
{int num;
public:A(int x = 10){}virtual void fun(){cout << "class A" << endl;}
};class B :public A
{int sum;
public:B(int x = 10){}virtual void fun(){cout << "class B" << endl;}
};int main()
{B b(10);A a(50);A* p = &b;return 0;
}

来看下面的代码分析:

 通过上面我们知道了虚函数的原理,下面我来看一下派生类中成员函数对父类的完全覆盖和部分覆盖的区别:

完全覆盖(基类中所有的虚函数都在子类中被重写)

class A
{int num;
public:A(int x = 10){}virtual void fun(){cout << "class A" << endl;}virtual void pun(){cout << "class A::pun" << endl;}
};class B :public A
{int sum;
public:B(int x = 10){}virtual void fun(){cout << "class B" << endl;}virtual void pun(){cout << "class B::pun" << endl;}};int main()
{B b(10);A* p = &b;p->fun();p->pun();return 0;
}

运行结果:都是调用B中的函数  没问题,符合我们的预期!

 部分覆盖(基类部分函数在派生类中没有进行重写或者是派生类声明了一些基类中没有的虚函数)

class A
{int num;
public:A(int x = 10){}virtual void fun(){cout << "class A" << endl;}virtual void pun(){cout << "class A::pun" << endl;}
};class B :public A
{int sum;
public:B(int x = 10){}virtual void fun(){cout << "class B" << endl;}virtual void show()    //将class B中的成员函数pun改成show函数{cout << "class B::pun" << endl;}};int main()
{B b(10);A* p = &b;p->fun();p->pun();return 0;
}

首先来看,p指向的函数有两个,fun和pun,但是没有我们刚刚改过的函数show,也就是说,如果在基类中没有的成员函数,但是在继承类中声明为虚函数,也不起作用,不能通过指针来指向。

 运行结果:

 因此想要派生类和基类在函数名相同但是实现不同功能的同时,必须函数名相同,如果在派生类中重写基类中没有的函数,声明为虚函数也没用,不可以通过上述代码中的指针或引用来调用。只可以通过实例化对象来实现对函数的调用(这块虽然show函数声明为虚函数,本质相当于普通成员函数)

总结:

1.父类子类虚函数之间的关系不是重载,而是重写(同名覆盖)。

2.父类指针指向派生类对象的地址,若在有派生类中有基类的重写成员函数,那么父类指针就可以通过虚表去调用派生类的同名覆盖的函数,如若派生类将 基类没有的函数 声明为virtual虚函数,那么就不可以通过基类的指针去之现象该函数,只可以 通过实例化派生类对象去调用这个普通成员函数。

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

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

相关文章

看了极光推送技术原理的几点思考

看了极光推送技术原理的几点思考 分类&#xff1a; android2012-11-26 20:50 16586人阅读 评论(18) 收藏 举报目录(?)[] 移动互联网应用现状 因为手机平台本身、电量、网络流量的限制&#xff0c;移动互联网应用在设计上跟传统 PC 上的应用很大不一样&#xff0c;需要根据手机…

【C++】多态(早期绑定、后期绑定)、抽象类(纯虚函数)、虚析构函数

我们都知道面向对象编程的三大特征是封装、继承、多态&#xff0c;今天我们就来说一下其中之一的多态。 概念&#xff1a; 多态&#xff1a; 多态字面意思就是多种形态&#xff0c;C 多态意味着调用成员函数时&#xff0c;会根据调用函数的对象的类型来执行不同的函数。(取自…

【C++】多线程thread

进程和线程这部分呢我之前在我Linux中写过这些东西&#xff0c;和C中线程的概念差不多&#xff0c;大家可以去看一下&#xff1a; Linux多线程_神厨小福贵&#xff01;的博客-CSDN博客进程和线程的区别有哪些呢&#xff1f;进程是资源分配的最小单位&#xff0c;线程是CPU调度…

【C++】多线程互斥锁、条件变量

我们了解互斥量和条件变量之前&#xff0c;我们先来看一下为什么要有互斥量和条件变量这两个东西&#xff0c;了解为什么有这两东西之后&#xff0c;理解起来后面的东西就简单很多了&#xff01;&#xff01;&#xff01; 先来看下面这段简单的代码&#xff1a; int g_num 0;…

【C++】二叉树的先序、中序、后序遍历序列

二叉树常用到的遍历有这三种 先序遍历&#xff1a;先遍历根节点&#xff0c;然后再分别遍历左节点和右节点。(根左右) 中序遍历&#xff1a;先遍历左节点&#xff0c;然后再遍历根节点&#xff0c;最后遍历右节点。(左根右) 后序遍历&#xff1a;先遍历左节点&#xff0c;然…

软件工程需求设计说明书

Java即时通聊天程序 设计需求说明书 专业班级&#xff1a; 计本班1202班 项目组成员&#xff1a; 杨宗坤 刘瑞 满亚洲 指导教师&#xff1a; 张利峰 开始日期&#xff1a; 完成日期&#xff1a; 编写目的&#xff1a; 本说明书是在充分理解系统需求分析…

【C++】菱形继承

我们先来看下菱形继承的基本视图以及基本的代码结构 下面来看下简单的代码以及数据结构&#xff1a; class Person { public:int a_p; };class Studen :public Person { public:int a_st; };class Stuff :public Person { public:int a_sf; };class st_sf :public Stuff, publ…

ie旋转滤镜Matrix

旋转一个元素算是一个比较常见的需求了吧&#xff0c;在支持CSS3的浏览器中可以使用transform很容易地实现&#xff0c;这里有介绍&#xff1a;http://www.css88.com/archives/2168&#xff0c;这里有演示http://www.css88.com/tool/css3Preview/Transform.html&#xff0c;就不…