先了解一些基础知识

1.构造函数和析构函数一般是公有成员,否则该类不能实例化

2.类成员默认访问权限是private类型(strcut默认访问权限是public)

3.析构函数一般是虚函数,否则可能会造成内存泄漏

4.拥有虚函数的的类都会有一个虚表,该虚表的指针位于类的首地址

虚表展示:

5.没有虚函数的类,首地址是成员变量(先后顺序和在类声明里面的一直,与公私有无关),

如果有虚函数,则类的成员变量从第5个位置开始放,前四个位置储放虚表地址

6.函数编译产生的地址与inline和virtual无关(产生地址是连续的)

7.打印成员变量和函数地址的方法

printf("成员变量m_char的地址:%p\n",&Base::m_char);

printf("成员函数funBase1的地址:%p\n",&Base::funBase1);

8.类空指针访问成员函数,但是如果drivedFun1是虚函数则会访问失败

这样的成员函数(非虚拟函数)与类实体不是存放在一起的。所以你调用时与实体是没关的。 但是如果是虚函数,就要用到vptr,这个是与类实体有关的,当然就不行了。static函数更是与实体没关的,也是可以调用的。 如果要深入理解,建议去看《深度探索C++对象模型》

进一步的测试

1.如果类指针没有访问类的虚函数和类指针的普通函数没有访问成员变量,则即使类指针即使为空该指针一样可以正常调用该函数(无所谓父类对象转为子类指针或者子类对象转为父类指针,甚至无所谓父子类)。

具体例子:

Drived d;

//Drived *pDrived = (Drived *)&d;  (2)

Drived *pDrived = NULL;         (3)

pDrived->drivedFun1();           (4)

代码行2和代码行3的赋值结果不会影响到代码行4的执行结果

2.每个拥有虚函数的类都有自己的虚表(下图展示了父子类虚表地址值的不同)

3.虚函数好处:父类指针指向子类对象可以调用子类函数,从而实现多态

原理:带有虚函数的类会产生一个虚表,虚表里有虚函数地址,程序执行时会动态加载

总结:虚函数的好处在于利用父类指针调用子类函数,当然也可以用子类指针指向父类对象,调用父类的函数,根据对象类型而定义函数,而不是指针类型。

问题:为什么非得继承?不具有继承关系的可以吗?如果不可以那么为什么不可以?

==================继承前(下面的父子类其实并无继承关系)==================

基类指针和子类指针结构:

把指向子类对象的指针强转为父类指针之后(pBase = (Base *)pDrived;)

观察pBase的变化

=================继承后(下面的父子类有了真实的继承关系)=================

基类指针和子类指针结构:

把指向子类对象的指针强转为父类指针之后(pBase = (Base *)pDrived;)

// VirtualFunction.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <stdio.h>

/类Base/

class Base

{

//测试默认访问权限

int test;

public:

char m_char[20];

int m_int;

public:

Base();

virtual ~Base();

public:

void funBase1();

void funBase2();

void funBase3();

virtual void commonFun();

};

Base::Base()

{

m_int = 0x11223344;

strcpy(m_char, "123456781234567");

}

Base::~Base()

{

}

void Base::funBase1()

{

printf("funBase1\n");

}

void Base::funBase2()

{

printf("funBase2\n");

}

void Base::funBase3()

{

printf("funBase3\n");

}

void Base::commonFun()

{

printf("commonFun in Base\n");

}

class Base2

{

public:

Base2(){};

virtual ~Base2(){};

public:

//virtual void commonFun();

};

// void Base2::commonFun()

// {

// //printf("commonFun in Base2");

// }

///类Drived/

class Drived : public Base, public Base2

{

public:

int m_int;

public:

Drived(){};

virtual ~Drived(){};

virtual void drivedFun1();

virtual void commonFun();

};

void Drived::drivedFun1()

{

printf("drivedFun1\n");

}

void Drived::commonFun()

{

printf("commonFun in Drived\n");

}

int _tmain(int argc, _TCHAR* argv[])

{

// printf("成员变量m_char的地址:%p\n",&Base::m_char);

// printf("成员变量m_int的地址:%p\n",&Base::m_int);

//

// printf("成员函数funBase1的地址:%p\n",&Base::funBase1);

// printf("成员函数funBase2的地址:%p\n",&Base::funBase2);

// printf("成员函数funBase3的地址:%p\n",&Base::funBase3);

Base b;

Base *pBase = (Base *)&b;

Drived d;

Drived *pDrived = (Drived *)&d;

// pBase = (Base *)pDrived;

// pBase->commonFun();

pBase = (Base *)pDrived;

pBase->drivedFun1();

return 0;

}

C++虚函数---我的理解相关推荐

  1. C++多态中虚函数的深入理解

    c++中动态多态性是通过虚函数来实现的.静态多态性是通过函数的重载来实现的,在程序运行前的一种早绑定,动态多态性则是程序运行过程中的一种后绑定.根据下面的例子进行说明. #include <io ...

  2. C++工作笔记-对纯虚函数的进一步理解(作用)

    对纯虚函数的理论不再说明. 本篇博文是为了说明他这个功能 代码如下: #include <iostream> #include <QString> #include <Q ...

  3. C++之------虚函数

    今天又是周日,公司工业区这里九月份每个周日都会停电一天.停电停网,是没法活的.我们直接去老大家. 老大当爸爸了,回家一段时间了.听说孩子出生就不乖,很折腾他爸妈,这小家伙新生命二代.也愿小家伙早日康复 ...

  4. C++ 静态函数与虚函数的区别

    经常在网上看到大家在讨论静态函数与虚函数的区别,往往可以看到统一的答案是:静态函数在编译的时候就已经确定运行时机,虚函数在运行的时候动态绑定.虚函数因为用了虚函数表机制,调用的时候会增加一次内存开销. ...

  5. C++ 虚函数详解(虚函数表、vfptr)——带虚函数表的内存分布图

    前言 总所周知,虚函数是实现多态的基础. 引用或指针的静态类型与对象本身的动态类型的不同,才是C++支持多态的根本所在. 当使用基类的引用或指针调用一个虚函数成员时,会执行动态绑定. 所有的虚函数都必 ...

  6. C++多态与虚函数的实现

    文章目录 多态 问题抛出 面向对象新需求 多态的意义探究 面向对象三大概念: 多态成立的三要素: 虚析构 函数的重载.重写.重定义 函数重载 函数重定义 虚函数重写 纯虚函数和抽象类 纯虚函数 抽象类 ...

  7. C++ 虚函数个人理解

    C++中的虚函数指的是class类中加上了关键字virtual的函数. 虚函数的意义在于动态绑定,也就是说父类指针可以调用子类的函数实现,示例如下: #include "stdio.h&qu ...

  8. 深入浅出理解c++虚函数

    深入浅出理解c++虚函数 记得几个月前看过C++虚函数的问题,当时其实就看懂了,最近笔试中遇到了虚函数竟然不太确定,所以还是理解的不深刻,所以想通过这篇文章来巩固下. 装逼一刻: 最近,本人思想发生了 ...

  9. C++深入理解虚函数

    c++深入理解虚函数 虚函数的使用方法: (1)在基类用virtual声明成员函数为虚函数.这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便被调用. 在类外定义虚函数时,不必在定义vir ...

最新文章

  1. 看完后,我才明白 Redis 为什么默认 16 个数据库?
  2. python sklearn.model_selection.ShuffleSplit()函数的用法
  3. c++函数模板(c++细节篇十)
  4. PHP学习笔记六【方法-递归】
  5. mybatis错误之配置文件属性配置问题
  6. java中集合的迭代操作
  7. BOM(浏览器对象模型)
  8. [Git] 我的 Github 地址
  9. 问题查询-批文页面显示别人操作的结果
  10. 【pyTranscriber】开源免费语音转字幕软件及替代方案
  11. xodo pdf android,手机上最好用的pdf阅读器,没有之一——【Xodo】
  12. android地图旋转监听,ArcGIS for Android示例解析之地图旋转-----MapRotation
  13. 工具 | IDEA 设置为护眼的豆沙绿
  14. php点击按钮保存图片到相册,手机端点击下载按钮将页面保存成图片到本地
  15. CSDN博客新增「评论置顶」、「定时发布」功能,翘首期盼的PC版「每日一练」上线!【第14期*2021.9.22】
  16. 国家、省、市、区四联动效果
  17. 学编程都会遇到哪些困难?
  18. ERROR: cannot launch node of type [fake_localization/fake_localization]: fake_localization
  19. 给女朋友写的h5(移动端)小游戏,超简单
  20. Media Encoder CC 2017安装使用攻略

热门文章

  1. SpringBoot的配置文件-通过@ConfigurationProperties映射数据
  2. plsql编程语言定义变量
  3. 使用RestTemplate模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别
  4. dw html 并排三个正方形边框,dw网页设计与制作题库(单选题)(43页)-原创力文档...
  5. 【报错笔记】运行Maven项目时发现项目Build错误
  6. error:cannot load driver JL2CM3.dll
  7. 建立一个通讯录的结构记录,包括姓名、年龄、电话号码
  8. 每月分享github上有意思的项目
  9. Python 爬取斗图啦图片
  10. css 宽高自适应的div 元素 如何居中 垂直居中