值为NULL的对象指针
相信大家对NULL不会很陌生,NULL 是一个标准规定的宏定义,用来表示空指针常量,当一个指针变量被赋值为NULL时,表示它不再指向任何有效地址,无法在访问任何数据。在VS2012库文件stdio.h中有如下定义:
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
NULL经常被用作指针初始化行为,以及free/delete某一指针后对其的赋值操作,这都是我们所鼓励的一些好的习惯操作。在对NULL指针进行解引用或者指向操作,会出现coredump或者其他undefined行为,而如果delete NULL指针的操作则是合法的。现在来看文中提到的值为NULL的对象指针,如下面的例子:
class A
{
public:
void foo()
{
cout<<"call foo"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A *p = NULL;
p->foo(); return ;
}
这里使用NULL指针p,调用成员函数foo(),运行时程序输出了“call foo",而没有coredump或者出现别的undefined行为,这是怎么回事呢?我们知道,对于类中的成员函数,隶属于所有类的对象,程序编译后,成员函数的地址已经确定,而成员函数访问类中的成员变量时,需要借助this指针对各个对象进行区分。看到类A的成员函数foo原型为void A::foo();,编译器会在发生函数在调用时,将其解释为void A::foo(A *const this);。注意这里的参数,this指针表示调用此函数的类A的对象地址。对于调用端,编译器将进行如下解释:
A a;
a.foo(); //->foo(&a);
A *p = NULL;
p->foo(); //->foo(p);
例子中传入的p为NULL,而在成员函数foo中,并未有用到通过this指针访问成员变量的语句,所以通过NULL指针调用foo时,得到了正确的结果。如果我们改一下类A的定义,添加成员变量,并且在foo中进行访问,如下:
class A
{
public:
void foo()
{
cout<<"call foo"<<endl;
cout<<"value = "<<value<<endl;
}
private:
int value;
};
这是仍然用p(NULL)指针来调用成员函数foo,则会使程序崩溃,因为编译器会将foo解释为:
void A::foo(A *const this)
{
cout<<"call foo"<<endl;
cout<<"value = "<<this->value<<endl;
}
这里传入的this为NULL,函数对NULL指针进行了指向操作,产生了为undefined行为。
this指针使得类的成员函数可以区分开各个对象之间的成员变量,那么如果类的成员变量属于类而不是属于类的对象呢,即static类型的成员对象
相信大家对NULL不会很陌生,NULL 是一个标准规定的宏定义,用来表示空指针常量,当一个指针变量被赋值为NULL时,表示它不再指向任何有效地址,无法在访问任何数据。在VS2012库文件stdio.h中有如下定义:
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
NULL经常被用作指针初始化行为,以及free/delete某一指针后对其的赋值操作,这都是我们所鼓励的一些好的习惯操作。在对NULL指针进行解引用或者指向操作,会出现coredump或者其他undefined行为,而如果delete NULL指针的操作则是合法的。现在来看文中提到的值为NULL的对象指针,如下面的例子:
class A
{
public:
void foo()
{
cout<<"call foo"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A *p = NULL;
p->foo(); return ;
}
这里使用NULL指针p,调用成员函数foo(),运行时程序输出了“call foo",而没有coredump或者出现别的undefined行为,这是怎么回事呢?我们知道,对于类中的成员函数,隶属于所有类的对象,程序编译后,成员函数的地址已经确定,而成员函数访问类中的成员变量时,需要借助this指针对各个对象进行区分。看到类A的成员函数foo原型为void A::foo();,编译器会在发生函数在调用时,将其解释为void A::foo(A *const this);。注意这里的参数,this指针表示调用此函数的类A的对象地址。对于调用端,编译器将进行如下解释:
A a;
a.foo(); //->foo(&a);
A *p = NULL;
p->foo(); //->foo(p);
例子中传入的p为NULL,而在成员函数foo中,并未有用到通过this指针访问成员变量的语句,所以通过NULL指针调用foo时,得到了正确的结果。如果我们改一下类A的定义,添加成员变量,并且在foo中进行访问,如下:
class A
{
public:
void foo()
{
cout<<"call foo"<<endl;
cout<<"value = "<<value<<endl;
}
private:
int value;
};
这是仍然用p(NULL)指针来调用成员函数foo,则会使程序崩溃,因为编译器会将foo解释为:
void A::foo(A *const this)
{
cout<<"call foo"<<endl;
cout<<"value = "<<this->value<<endl;
}
这里传入的this为NULL,函数对NULL指针进行了指向操作,产生了为undefined行为。
对于C++中类的静态函数,它只能访问类的静态成员变量,因为在编译器对静态函数的解释不会包含this指针,根据这种特性,我们知道NULL指针同样可以调用类中的静态成员函数,以此访问静态成员变量:
class A
{
public:
static void foo()
{
cout<<"call foo"<<endl;
cout<<"value = "<<value<<endl;
}
private:
static int value;
};
int A::value = ; int _tmain(int argc, _TCHAR* argv[])
{
A *p = NULL;
p->foo();
return ;
}
我们知道类的成员函数中可以定义普通函数、静态函数、还可以定义虚函数,已实现多态的效果,那么对于类中的虚函数,用NULL指针调用时会有怎样的后果呢,将上面的代码简单修改下:
class A
{
public:
virtual void foo()
{
cout<<"call foo"<<endl;
}
private:
int value;
};
int _tmain(int argc, _TCHAR* argv[])
{
A *p = NULL;
p->foo(); return ;
}
运行的结果竟然崩溃,foo函数和之前一样,没有访问成员变量value,不会出现NULL指针指向的问题,但程序为何崩溃了呢?原因在于foo函数被定义为了虚函数,这些虚函数中的地址(函数指针)保存在虚函数表中,可以将它看做一个函数指针数组(列表),含有虚函数的类拥有一张虚函数表,而此类的每一个对象在构造时,由编译器将一个指向虚函数表的指针安插进来,成为虚表指针,而它的作用是在我们调用虚函数时,能更准确的访问到虚函数表中此函数的指针,从而进行调用。回过头来看看之前的例子,我们根据类A的NULL指针p调用它的虚函数,而此时由于没有进行初始化,所以虚指针没有安插进去,所以程序崩溃。
值为NULL的对象指针的更多相关文章
- @JsonInclude注解,RestTemplate传输值为null的属性,利用FastJson将属性中有空值null的对象转化成Json字符串
一个pojo类: import lombok.Data; @Data public class Friend { private String name; private int age; priva ...
- spring mvc 处理pojo传递对象时该对象继承父类的属性在网络接收端接收该属性值总是null,why?
//=========================== 情形一: ===============================//在网络上传递User1类对象时info属性值在网络的另一端能够接 ...
- java对象json序列化时忽略值为null的属性
环境: jdk: openjdk11 操作系统: windows 10教育版1903 目的: 如题,当一个对象里有些属性值为null 的不想参与json序列化时,可以添加如下注解 import com ...
- mybatis查询返回的对象不为null,但是属性值为null
返回的对象不为null,但是属性值为null 代码如下: <resultMap id="BaseResultMap" type="com.trhui.ebook.d ...
- js对象转换为json格式时,js对象属性中有值为null和undefined注意事项
当属性值为null时: 当属性值为undefined时: 只有当属性值为未定义时, js对象转换成json格式时会忽略该属性.
- 黑马程序员-nil Nil NULL NSNull 野指针和空指针
空指针1.空指针指不含有任何内存地址的指针.在没有具体初始化之前,其被符值为0Dog * dog = nil;Dog * dog = NULL;都为空指针2.野指针指指向的内存为垃圾内存,导致其值不确 ...
- c++中的对象引用(object reference)与对象指针的区别
★ 相同点: 1. 都是地址的概念: 指针指向一块内存,它的内容是所指内存的地址:引用是某块内存的别名. ★ 区别: 1. 指针是一个实体,而引用仅是个别名: 2. 引用使用时无需解引用(*),指针需 ...
- delete指针以后应赋值为NULL——QT deletelater指针以后也同样要马上赋值为NULL
delete p后,只是释放了指针指向的内存空间.p并不会自动被置为NULL,而且指针还在,同时还指向了之前的地址 delete NULL编译器不会报错(因为delete空指针是合法的) 例: 对一个 ...
- c++值传递和引用及指针传递区别
以下程序各有何问题? ***************************************************************************************** ...
随机推荐
- Android Drawable绘图学习笔记(转)
如何获取 res 中的资源 数据包package:android.content.res 主要类:Resources Android SDK中的简介:Class for accessing an ap ...
- HTTPS抓包配置
以Charles为例 配置Charles抓取Https需要手机和PC分别进行配置. 步骤: 1.PC下载charles客户端,并安装. 2.charles客户端安装证书 注意证书安装需要保存在&quo ...
- 使用Django清理数据库中的数据
数据库,数据清洗 问题叙述性说明:在系统我用在,因为历史和由于各种原因,原因记录的数据内的数据库表,有一个问题,有反复和不完整的数据 解:首先.由于数据量还是挺大的,工的清理肯定不行, 然后,我就想写 ...
- about greenplum collection tool
three collection tool for greenplum:pstack.strace.gcore. ...
- 网络资源(2) - Maven视频
2014_08_23 http://v.youku.com/v_show/id_XNDE2NzM0Nzk2.html Maven最佳实践,公司真实环境实践-私服最佳实践 2014_08_24 http ...
- java 获取系统变量(环境变量和环境变量)
前言 环境变量这个概念不陌生, 就是操作系统的环境变量. 系统变量就是java本身维护的变量. 通过 System.getProperty 的方式获取. 对于不同的操作系统来说. 环境变量的处理可能会 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(19)-用户信息的修改和浏览
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(19)-用户信息的修改和浏览 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 ...
- linux_shell_根据网站来源分桶
应用场景: 3kw行url+\t+html记录 [网站混合] 需要:按照网站来源分桶输出 执行shell cat */*pack.html|awk -F '\t' '{ split($1,arr,&q ...
- hdu1286 寻找新朋友 (欧拉功能)
原标题:点击打开链接 关于欧拉函数的算法具体解说:点击打开链接 欧拉函数 1.欧拉函数是不全然积性函数. 2.欧拉函数p(x) = x * (p1 - 1) / p1 * (p2 - 1)/p2 * ...
- ReactJS.NET 开发
初探ReactJS.NET 开发 ReactJS通常也被称为"React",是一个刚刚在这场游戏中登场的新手.它由Facebook创建,并在2013年首次发布.Facebook ...