C++虚函数作用原理(一)——虚函数如何在C++语言逻辑中存在
C++多态,接触其实也没太长的时间。上课的时候老师总是不停的讲,多态可以实现利用一个基类对象调用不同继承类的成员函数。我就会觉得很伤脑筋,这个的原理到底是什么?是什么呢?
开始的时候我觉得自己应该能够把它的原理想出来,因为一直觉得关于这些高级语言的事情,不论看起来多么神奇,其实应该都是之前学的基础累积起来的。所以,我就自己想了一段时间————能够实现这样效果的只有 指针 了。
但是这个指针应该怎么定义呢?就算基类中本身定义了一个指针,可是继承类中被继承来的函数在利用基类的时候怎么告诉基类到底调用哪一个继承类的函数呢?真的伤脑筋。
……
现在是开始这个博客的第二天,我终于可以开始继续写了——因为我开始自己调试观察虚函数。
OK,现在开始了:
首先:
一、没有继承的类
(1)段小小的代码:
class A
{
int x;
int y;
public:
virtual void out()
{
cout << x << y << endl;
cout<<"A"<<endl;
}
};
int main()
{
A a;
return 0;
}
十分明显这段程序中仅仅只有一个类,一个虚函数!现在我们一起来看看类A的成员到底如何分布的。
成员变量x和y存在。同时出现了 _vptr 。它是什么?没错儿就是虚函数表指针。也就是说这个_vptr就是指向虚函数表(或者理解它为指向,存有所有虚函数地址的一个数组的指针)的一个指针!
现在我们点开_vptr发现:
它里面仍然是一个指针但是这个是指向我们唯一的虚函数void out()的指针!
总结:
通过上面的观察,我们知道了虚函数是由虚函数表里面存储的地址通过寻址的方式来实现的。那么就意味着我们可以直接通过地址来调用函数!这里我们也可以通过一段代码验证我所述的是否为真。
首先我们要获得虚函数表指针:
int main()
{
A a;
int *_Avptr;
_Avptr = (int *)&a;//获得虚函数表指针,并通过强制转化为(int*)型。
return 0;
}
获得虚函数指针
int main()
{
A a;
int *_Avptr;
int *Varr;
_Avptr = (int *)&a;//获得虚函数表指针,并通过强制转化为int*型。
Varr = (int *)*(_Avptr);//获得虚函数指针。
return 0;
}
直接通过指针调用函数
```typedef void(*pFUNC)(void);//定义一个无返回值,无参数的指针型函数。
```
```
int main()
{
A a;
int *_Avptr;
int *Varr;
_Avptr = (int *)&a;//获得虚函数表指针,并通过强制转化为int型。
Varr = (int *)*(_Avptr);//获得虚函数指针。
pFUNC pfunc1 = (pFUNC)*Varr;//开始利用地址直接访问虚函数
pfunc1();
return 0;
}
###运行结果:

virtual void out()
{
cout << x << y << endl;
cout<<"A"<<endl;
}
输出内容和我们虚函数中写的函数需要我们输出的无异议。所以证明了我们之前的想法。
现在,对虚函数到底是怎么存在的应该没有什么问题了。
C++虚函数作用原理(一)——虚函数如何在C++语言逻辑中存在的更多相关文章
- 【C++】多态性(函数重载与虚函数)
多态性就是同一符号或名字在不同情况下具有不同解释的现象.多态性有两种表现形式: 编译时多态性:同一对象收到相同的消息却产生不同的函数调用,一般通过函数重载来实现,在编译时就实现了绑定,属于静态绑定. ...
- c++ 虚函数和纯虚函数
在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的.从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现.通过这样的方法,就可以将对象 ...
- C++ - 虚基类、虚函数与纯虚函数
虚基类 在说明其作用前先看一段代码 class A{public: int iValue;}; class B:public A{public: void bPrintf(){ ...
- C++中不能声明为虚函数的有哪些函数
常见的不不能声明为虚函数的有:普通函数(非成员函数):静态成员函数:内联成员函数:构造函数:友元函数. 1.为什么C++不支持普通函数为虚函数? 普通函数(非成员函数)只能被overload,不能被o ...
- TWinControl与TControl的覆盖函数(TWinControl对TControl的10个消息覆盖函数,17个覆盖函数,私有虚函数仍可多态)
手工找出来,对比一下,有助于VCL框架的理解.----------------------------------------------------------------------------- ...
- C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类
类继承 在C++类继承中,一个派生类可以从一个基类派生,也可以从多个基类派生. 从一个基类派生的继承称为单继承:从多个基类派生的继承称为多继承. //单继承的定义 class B:public A { ...
- C++ Primer--虚函数与纯虚函数的区别
首先:强调一个概念 定义一个函数为虚函数,不代表函数为不被实现的函数. 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数. 定义一个函数为纯虚函数,才代表函数没有被实现. 定义纯虚函数是为了实 ...
- C++ 虚函数与纯虚函数
#include<iostream> #include<string> using namespace std; class A{ public: virtual void f ...
- c++中虚函数和纯虚函数定义
只有用virtual声明类的成员函数,使之成为虚函数,不能将类外的普通函数声明为虚函数.因为虚函数的作用是允许在派生类中对基类的虚函数重新定义.所以虚函数只能用于类的继承层次结构中. 一个成员函数被声 ...
随机推荐
- HashPump用法
做哈希长度扩展攻击的时候用到这个工具,但是没找到这个工具详解办法 我这篇不算是详解,只是收集例子做出的一个用法 HashPump一种在各种散列算法中利用散列长度扩展攻击的工具.目前支持的算法:MD5, ...
- CSP考试策略
准备 带好手表,身份证,准考证,文具,和矿泉水(热水). 考试之前 如果时间比较充足,可以重启测试保护是否解开. 调整显示屏亮度,检查键盘.鼠标. 关掉拓展名隐藏. 写个简单程序测试是否有异常,测试对 ...
- python脚本调用外部程序的若干种方式以及利弊
脚本执行外部程序的常用几种方式: # os.popen(path)# subprocess.run(cmd,shell=True)# subprocess.check_call(cmd,shell = ...
- [bzoj2288]【POJ Challenge】生日礼物_贪心_堆
[POJ Challenge]生日礼物 题目大意:给定一个长度为$n$的序列,允许选择不超过$m$个连续的部分,求元素之和的最大值. 数据范围:$1\le n, m\le 10^5$. 题解: 显然的 ...
- [转帖]postgresql 在等待服务器启动时超时
postgresql 在等待服务器启动时超时 2018年12月24日 :: my_name_nb 阅读数 版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接 ...
- python 小数据池,代码块, is == 深入剖析
python小数据池,代码块的最详细.深入剖析 一. id is == 二. 代码块 三. 小数据池 四. 总结 一,id,is,== 在Python中,id是什么?id是内存地址,那就有人问了, ...
- Tomcat: has been normalized to [null] which is not valid
环境 tomcat 8.5 原因 在使用相对路径加载配置文件时,如果相对路径超出了 tomcat 容器的根目录,那么 tomcat 会提示 xxx has been normalized to [nu ...
- Arrays.asList()方法注意事项
1.Arrays.asList()底层数组作为物理层实现.所以返回的List大小不可更改,即不可以做add().remove()操作,并且对List所做的任何变动都会致使原数组发生变动. public ...
- winform中如何使用确认对话框
在系统中,常需要这样的功能,让用户确认一些信息:如下图: [退出系统]按钮关键代码如下: private void btnExit_Click(object sender, EventArgs e) ...
- centos编译安装python3怎么做?
照着我的博客操作 你一定能成功的!因为我就是一步一步的做出来的,虽然只有文档,但是希望你能有耐心!!!! 编译安装难么麻烦,为什么还要编译安装? 那我告诉你想进步就要折腾!你习惯了windows的安装 ...