做项目的过程中,碰到一个问题。

问题可以抽象为下面的问题:

普通人吃饭拿筷子,小孩吃饭拿勺子。

class People {
public:
void eat() {
get_util_to_eat();
} virtual void get_util_to_eat() {
std::cout << "People get chopsticks" << std::endl;
}
}; class Children : public People {
public:
void get_util_to_eat() {
std::cout << "Children get scoop" << std::endl;
}
}; int main() {
People* people = new Children();
people->eat();
return ;
}

输出结果:

Children get scoop

当然这也符合我们的预期。

因为people不是虚函数,所以上述程序调用的是people中的eat方法,这就涉及到一个之前我一直模糊的概念,在一个类方法中调用虚方法,是如何调用的。

这又涉及到之前不得不说的一个问题:

class A {
public:
void print() {
std::cout << "i am A" << std::endl;
}
}; int main() {
A* a = NULL;
a->print();
return ;
}

上述代码会输出什么,按照直观的感觉NULL怎么可能调用方法呢,要出core吧。

但是事实上,输出的是:

i am A

调用类函数的时候,c++编译器并不会管该类是否为空,而是将该类的地址当做this指针传到函数中去。

a->print() 时,在编译器中就相当于print(a)

有因为print中没有用到成员变量的情况,所以自然能很正确的运行。

然后来看下汇编代码就能更理解了。以下是People类内的汇编代码。

        void eat() {
0x0000000000400bd2 <+>: push %rbp
0x0000000000400bd3 <+>: mov %rsp,%rbp
0x0000000000400bd6 <+>: sub $0x10,%rsp
0x0000000000400bda <+>: mov %rdi,-0x8(%rbp) //rsp表示第一个参数,也就是类的指针
get_util_to_eat();
0x0000000000400be9 <+>: mov -0x8(%rbp),%rax //将类指针放入rax寄存器中
0x0000000000400bed <+>: mov (%rax),%rax //取首地址值,也就是虚表地址
0x0000000000400bf0 <+>: mov -0x8(%rbp),%rdi //放入rdi中,下次函数调用的时候取参用
0x0000000000400bf4 <+>: mov (%rax),%rax //取出虚表中函数的地址
0x0000000000400bf7 <+>: callq *%rax //调用改函数

总结就是,进入类的非静态成员函数时,会默认携带类的指针(this),然后改函数内用到成员变量、成员方法都等同于在前面加了一个this->

So 回到最初的那个问题,在People::eat中传入的是Chilren的指针,所以调用 get_util_to_eat 时从虚表中取出了Children::get_util_to_eat方法并进行调用。

c++ 类内部函数调用虚函数的更多相关文章

  1. C++构造函数和析构函数调用虚函数时都不会使用动态联编

    先看一个例子: #include <iostream> using namespace std; class A{ public: A() { show(); } virtual void ...

  2. C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类

    类继承 在C++类继承中,一个派生类可以从一个基类派生,也可以从多个基类派生. 从一个基类派生的继承称为单继承:从多个基类派生的继承称为多继承. //单继承的定义 class B:public A { ...

  3. C++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构

    一.基类指针.派生类指针 父类指针可以new一个子类对象 二.虚函数 有没有一个解决方法,使我们只定义一个对象指针,就可以调用父类,以及各个子类的同名函数? 有解决方案,这个对象指针必须是一个父类类型 ...

  4. 自绘CListCtrl类,重载虚函数DrawItem

    //自绘CListCtrl类,重载虚函数DrawItem void CNewListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // TOD ...

  5. 继承虚函数浅谈 c++ 类,继承类,有虚函数的类,虚拟继承的类的内存布局,使用vs2010打印布局结果。

    本文笔者在青岛逛街的时候突然想到的...最近就有想写几篇关于继承虚函数的笔记,所以回家到之后就奋笔疾书的写出来发布了 应用sizeof函数求类巨细这个问题在很多面试,口试题中很轻易考,而涉及到类的时候 ...

  6. C++:抽象基类和纯虚函数的理解

    转载地址:http://blog.csdn.net/acs713/article/details/7352440 抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层. ...

  7. (转)(C++)关于抽象基类和纯虚函数

    ★抽象类:一个类可以抽象出不同的对象来表达一个抽象的概念和通用的接口,这个类不能实例化(创造)对象. ★纯虚函数(pure virtual):在本类里不能有实现(描述功能),实现需要在子类中实现.例: ...

  8. C++入门经典-例8.9-抽象类,纯虚函数,创建纯虚函数

    1:包含有纯虚函数的类称为抽象类,一个抽象类至少具有一个纯虚函数.抽象类只能作为基类派生出的新的子类,而不能在程序中被实例化(即不能说明抽象类的对象),但是可以使用指向抽象类的指针.在程序开发过程中并 ...

  9. C++ 构造函数或析构函数调用虚函数

    构造函数和析构函数中的虚函数 在执行基类构造函数时,对象的派生类部分是未初始化的.实际上,此时对象还不是一个派生类对象. 为 了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化.在基类 ...

随机推荐

  1. (转)android系统架构及源码目录结构

    转自:http://blog.csdn.net/finewind/article/details/46324507 1. Android系统架构: android系统架构采用了分层架构的思想,如下图所 ...

  2. JSON数组,JSON对象,数组的区别与基本操作整理

    JSON 语法规则 JSON 语法是 javascript 对象表示语法的子集. 数据在名称/值对中 数据由逗号分隔 花括号保存对象 方括号保存数组 JSON 名称/值对 JSON 数据的书写格式是: ...

  3. linux环境下获取真实的ip地址

    package inas.test; import java.net.Inet6Address; import java.net.InetAddress; import java.net.Networ ...

  4. 8.1 shell介绍 8.2 命令历史 8.3 命令补全和别名 8.4 通配符 8.5 输入输出重定向 

    8.1 shell介绍 8.2 命令历史 8.3 命令补全和别名 8.4 通配符 8.5 输入输出重定向 什么是shell? shell是一个命令解释器,提供用户和及其之间的交互 致辞特定语法,比如逻 ...

  5. ping telnet ssh netstat

    1.pingping命令工作在OSI参考模型的第三层-网络层.ping命令会发送一个数据包到目的主机,然后等待从目的主机接收回复数据包,当目的主机接收到这个数据包时,为源主机发送回复数据包,这个测试命 ...

  6. result源码

    CREATE TABLE `result` (`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,`thetime` CHAR(100) , `category ...

  7. VS2012:升级Update2和Update3均告损坏,重装方法

    My steps (after backing up everything before deleting it): 1. Uninstalled VS2012 Pro from Windows 8 ...

  8. GridView动态添加列并判断绑定数据DataTable的列类型控制展示内容

    此篇随笔是2013年根据项目需求开发记录的,不一定符合大众口味,只需了解开发思路,毕竟解决方案多种多样. 下面简单说说需求点吧: (1)通过下拉列表可以选择一个DataSet(数据集),一个DataS ...

  9. SharePoint 2013 显示“以其他用户身份登录”菜单项

    最近在SharePoint 2013的网站上发现,没有看到有切换不同用户登录的入口,在SharePoint 2010中是存在这样的菜单项能够很方便的进行用户切换的,不知道为什么,SharePoint ...

  10. Android Material Design控件学习(二)——NavigationView的学习和使用

    前言 上次我们学习了TabLayout的用法,今天我们继续学习MaterialDesign(简称MD)控件--NavigationView. 正如其名,NavigationView,导航View.一般 ...