vfptr(2)
//i_vptr
struct i_vptr
{
virtual void test() = ;
};
//vptr.h
#include "i_vptr.h"
#include <iostream>
class vptr:public i_vptr
{
public:
void test(); };
//vptr.cpp
#include "vptr.h"
void vptr::test()
{
std::cout << "hhhh" << std::endl;
}
//main.cpp
#include "vptr.h"
int main()
{
//这个可以说是我特别晕的,我想到基类的指针怎么会调用到派生类的函数
//vptr从i_vptr继承,就继承了他的vfptr,vfptr指向vtable,每个类有一个vtable
i_vptr* p = new vptr;//会发生切割,切割掉i_vptr没有的东西,所以这个vfptr不会被切割掉,所以指向的还是派生类的vfptr
p->test();//通过vfptr查找vtable,r就可以找到相应的函数地址,所以调用的还是派生类的函数
system("pause");
return ;
}
//下面我觉得挺有用的
需要知道一些常识,一个类所有的函数都是再code代码区中唯一的存放一份。而数据成员则是每个对象存储一份,并按照声明顺序依次存放。
类A中有了虚函数就会再类的数据成员的最前面添加一个vfptr指针(void** vfptr),这个指针用来指向一个vtable表(一个函数指针数组)(一个类只有一个该表),该表存储着当前类的所有 虚函数 的地址。这样vfptr就成为了一个类似成员变量的存在。访问虚函数的时候通过vfptr间址找到vtable表,再间址进而找到要调用的函数。这样就在一定程度上摆脱了类型制约。
只要vptr的值不同,那么访问函数成员的时候使用的vtable表就不同,就可能访问到不同类的函数成员。B类对象中的vptr指向B类自己的vtable。
当B类继承A类的时候,因为A中有虚函数,编译器就自动的给B类添加vfprt指针和vtable表。也可以理解为B类继承来了A类中的那个vptr指针成员。
当A类指针指向B类对象时,发生假切割。要知道这个过程只是切掉A类中没有的那些成员,由于vptr是从A类中继承来的,所以这个量仍将保留。而对于vptr的值则不会改变,仍然指向B类的vtable表。所以访问F1函数的时候是通过B类的vtable表去寻址的,自然就是使用子类的函数。
当B类的指针指向A类的对象时(当B类存在新增数据成员时可能出错),同理。
而对于普通函数则受类型的制约,(因为没有vptr指针)使用哪个类的指针调用函数,那么所调用的就是那个累的函数。
总而言之,普通函数通过对象或指针的类型来找所调用的函数,而虚函数是通过一个指针来找到所要调用的函数的。
vfptr(2)的更多相关文章
- 虚继承之单继承的内存布局(VC在编译时会把vfptr放到类的头部,这和Delphi完全一致)
		
C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼.虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内 ...
 - vfptr(1)
		
前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛 ...
 - 图说C++对象模型:对象内存布局详解
		
0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...
 - C++基础_总结
		
(1)多态性都有哪些?(静态和动态,然后分别叙述了一下虚函数和函数重载) 多态分为两种:静态和动态.静态主要包括函数重载和模板:动态主要是依靠虚函数实现的. 静态联编:重载函数不加virtual关键字 ...
 - C++类内存布局图(成员函数和成员变量分开讨论)
		
一.成员函数 成员函数可以被看作是类作用域的全局函数,不在对象分配的空间里,只有虚函数才会在类对象里有一个指针,存放虚函数的地址等相关信息. 成员函数的地址,编译期就已确定,并静态绑定或动态的绑定在对 ...
 - C++ 类继承的对象布局
		
C++多重继承下,对象布局与编译器,是否为虚拟继承都有很大关系,下面将逐一分析其中的差别,相同点为都按照类继承的先后顺序布局(类内按照虚表.成员声明先后顺序排列).该类情况为子类按照继承顺序排列,如c ...
 - C++对象模型
		
1.类布局 1.1简单类对象的内存布局 class A { public: void f(); private: int i; char c; static int s; }; 简单对象的内存布局:非 ...
 - 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算  32位机器上 sizeof(void *) // 4byte
		
#include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...
 - C++类内存分布
		
http://www.cnblogs.com/jerry19880126/p/3616999.html#undefined 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看 ...
 
随机推荐
- npm添加淘宝镜像
			
原文:http://cnodejs.org/topic/4f9904f9407edba21468f31e npm是一个很好用的工具,全场是Node Packet Manager,是一个nodejs的包 ...
 - linux 压缩、解压缩及归档工具
			
linux下主要的压缩.归档工具 compress/uncompress: .Z gzip/gunzip: .gz bzip2/bunzip2: .bz2 xz/unxz: .xz zip/unzi ...
 - There is insufficient memory for the Java Runtime Environment to continue问题解决
			
在linux系统下长时间进行性能測试,连续几次发生server假死无法连接上的情况,无奈仅仅能重新启动server.在測试路径下发现hs_err_pid17285.log文件,打开文件查看其主要内容例 ...
 - java之this关键字
			
this使用范围 1.在类的方法定义中使用的this关键字代表调用该方法对象的引用. 2.当必须指出当前使用方法的对象是谁时,要使用关键字this. 3.有时使用this可以处理方法中成员变量和参数重 ...
 - Mylyn--谁用谁知道!
			
Mylyn――谁用谁知道!http://www.blogjava.net/alwayscy/archive/2008/06/15/208022.html 此文是我之Mylyn初体验,不搞大而全,而只把 ...
 - AngularJs学习笔记(4)——自定义指令
			
对指令的第一印象:它是一个自定义标签! 先来看一个简单的指令: <!doctype html> <html ng-app="myApp"> <head ...
 - Python进程、线程、协程之间的关系
			
一.从操作系统角度 操作系统处理任务, 调度单位是 进程 和 线程 . 1.进程: 表示一个程序的执行活动 (打开程序.读写程序数据.关闭程序) 2.线程: 执行某个程序时, 该进程调度的最小执行单位 ...
 - ZOJ 3827 Information Entropy (2014牡丹江区域赛)
			
题目链接:ZOJ 3827 Information Entropy 依据题目的公式算吧,那个极限是0 AC代码: #include <stdio.h> #include <strin ...
 - Phaser实现源代码剖析
			
Phaser是一个能够反复利用的同步栅栏.功能上与CyclicBarrier和CountDownLatch相似,只是提供更加灵活的使用方法.也就是说,Phaser的同步模型与它们几乎相同. 一般运用的 ...
 - php的pear包管理
			
1.安装: $ sudo wget http://pear.php.net/go-pear.phar $ sudo php go-pear.har 2.查看pear下安装的包: $ pear l ...