引出:写个类A,声明类A指针指向NULL,调用类A的方法会有什么后果,编译通过吗,运行会通过吗?

(在VS2008与VC++的情况下) 有错误欢迎批评指正!

#include<stdio.h>
#include<iostream>
using namespace std; class base{
int a;
public:
void fun(){
printf("base fun\n");
}
}; int main(){
base *b=NULL;
b->fun();
}

看到这个的时候,一定以为运行会报错吧。

但是奇迹般的,编译器输出了:base fun

#include<stdio.h>
#include<iostream>
using namespace std; class base{
int a;
public:
virtual void fun(){
printf("base fun\n");
}
}; int main(){
base *b=NULL;
b->fun();
}

在看这个代码,还以为会输出base fun么,又错了,运行报错!

为什么会是这个结果?

#include<stdio.h>
#include<iostream>
using namespace std; class base{
int a;
public:
virtual void fun(){
printf("base fun\n");
}
void fun2(){
printf("base fun\n");
}
}; int main(){
base *b=NULL;
b->fun();
b->fun2();
}

可以发现,一个是虚函数,一个普通函数

在观察下内存中得情况:

发现果然虚函数还没在内存中,而fun2已经在内存中了

在看看汇编:

明显发现虚函数的调用比普通函数多了好几个步骤,

ecx 中放的this 指针,所以this=0(NULL),但是普通函数fun2放在全局内存区,所以可以访问

而虚函数是根据虚函数表寻找的,这时没有虚函数表,自然就没法查到虚函数的地址了

感谢 hoodlum1980 更详细的说明:因为非虚函数的地址对编译期来说“静态”的,也就是函数地址在编译期就已经确定了,实例地址对于非虚函数只是那个 this 指针参数。所以只要不访问类的实例数据就没什么问题。而虚函数的地址,是先到实例的地址前面去查找它的虚函数表所在的地址。然后从虚函数表里取出该函数所对应的元素(虚函数表是一个函数指针数组)来call的。(当然一个已知的类的虚函数表的内容也是编译期静态的,但不同类的虚函数表内容不同,即运行时多态的基础)所以实例如果为NULL,是个有特殊意义的值,是会触发运行时错误的。

总结:类中的虚函数是动态生成的,由虚函数表的指向进行访问,不为类的对象分配内存,就没有虚函数表就无法访问。

   类中的普通函数静态生成,不为类的对象分配内存也可访问。

指向NULL的类的更多相关文章

  1. c++,基类声明的指针变量和引用类型变量可以指向派 生类的对象

    基类声明的指针变量和引用类型变量可以指向派生类的对象,而反过来派生类的指针却不能指向基类变量. 这与基类和派生类之间,被允许的赋值方向是相反的. 但是从逻辑上很容易推敲其合理性.

  2. .NET面试题系列[11] - IEnumerable<T>的派生类

    “你每次都选择合适的数据结构了吗?” - Jeffery Zhao .NET面试题系列目录 ICollection<T>继承IEnumerable<T>.在其基础上,增加了Ad ...

  3. Objective-C Runtime 运行时之一:类与对象

    Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一 ...

  4. Guava学习笔记(1):Optional优雅的使用null

    转自:http://www.cnblogs.com/peida/archive/2013/06/14/Guava_Optional.html 参考:[Google Guava] 1.1-使用和避免nu ...

  5. iOS RunTime运行时(1):类与对象

    Objective-C语言是一门动态语言,他将很多静态语言在编译和链接期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码更具有灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一下 ...

  6. (转)c++类的成员函数存储方式(是否属于类的对象)---一道面试题引发的思考

    昨天去面试一家公司,面试题中有一个题,自己没弄清楚,先记录如下: class D { public: void printA() { cout<<"printA"< ...

  7. [BS-22] Objective-C中nil、Nil、NULL、NSNull的区别

    Objective-C中nil.Nil.NULL.NSNull的区别 1.定义: nil:      OC语言定义:#define nil __DARWIN_NULL   /  #define __D ...

  8. null&this&super&向上转型

    向上转型:父类声明子类实例化对象 例如A是父类 B是子类    1 : 实际上是父类的对象但将会丢失子类没有的父类方法 ,如果调用方法 将会调用子类重写的父类方法    2:上转型对象不能调用子类新增 ...

  9. C Primer Plus之存储类、链接和内存管理

    存储时期即生存周期——变量在内存中保留的时间 变量的作用域和链接一起表明程序的哪些部分可以通过变量名来使用该变量. 注意:生存期和作用域是两个不同的概念. 作用域    作用域描述了程序中可以访问一个 ...

随机推荐

  1. 20155201 实验五《Java面向对象程序设计》实验报告

    20155201 实验五<Java面向对象程序设计>实验报告 一.实验内容 1. 数据结构应用 2. 结对编程:利用IDEA完成网络编程任务,1人负责客户端,1人负责服务器 3. 密码结对 ...

  2. 在pom.xml中使用distributionManagement将项目打包上传到nexus私服

    本文介绍 如何在pom.xml中使用distributionManagement将项目打包上传到nexus私服 1.pom.xml文件添加distributionManagement节点 <!- ...

  3. myeclipse删除项目后重新导入

    今天安装了myeclipse2017版,刚开始导入项目后然后删除了,发现再次导入进来的时候不可以了. 解决方法:点击file -- >switch workspace -- >other ...

  4. Git-时光穿梭【转】

    本文转载自:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 时光穿梭机 我们已经成 ...

  5. UVA 257 Palinwords(hash)题解

    思路:给你字符串,如果他包含至少两个长度大于等于3的回文,并且这些回文不能嵌套(例如aaa嵌套在aaaa,waw嵌套在awawa),如果这个字符串这么牛逼的话,就输出他. 思路:拿到字符串先正序has ...

  6. node scripts/install.js 停顿解决办法

    参考:node-sass 安装卡在 node scripts/install.js 解决办法 在安装hexo的时候,运行: npm install hexo-cli -g 卡死在了 node scri ...

  7. python 去除不可见的控制字符

    尤其是在json load的时候,字符串中的不可见控制字符可能会导致错误,应该先对字符串进行控制字符过滤. 对网页文本同样适用,最好在处理网页文本时先进性控制字符清洗. Replace null by ...

  8. 【Python】远离 Python 最差实践,避免挖坑

    原文链接:http://blog.guoyb.com/2016/12/03/bad-py-style/ 最近在看一些陈年老系统,其中有一些不好的代码习惯遗留下来的坑:加上最近自己也写了一段烂代码导致服 ...

  9. git-it 教程,一些git知识点。/ 如何解决merge conflict/ 如何使用Github Pages./Git术语表

    一个git使用教程 https://:.com/jlord/git-it-electron#what-to-install 一个在线Github的功能教学:https://lab.github.com ...

  10. IOS-如何优雅地拦截按钮事件(判断是否需要登录)

    关于这个标题,起因是这样的. 最近一次做项目需求时,遇到这样一个需求,就是本来我们App是必须注册或者第三方登录才可以使用,现在希望不登录也可以浏览App里面的内容,只是在需要的时候才提示登录,并且在 ...