值为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++值传递和引用及指针传递区别
以下程序各有何问题? ***************************************************************************************** ...
随机推荐
- 应用spss可靠性分析软件
问卷调查的可靠性分析 一.概念: 信度是指依据測验工具所得到的结果的一致性或稳定性,反映被測特征真实程度的指标. 一般而言,两次或两个測验的结果愈是一致.则误差愈小,所得的信度愈高,它具有下面 ...
- Scrapy研究和探索(五岁以下儿童)——爬行自己主动多页(抢别人博客所有文章)
首先.在教程(二)(http://blog.csdn.net/u012150179/article/details/32911511)中,研究的是爬取单个网页的方法.在教程(三)(http://blo ...
- asp.net学习之 数据绑定控件--List数据绑定控件
原文:asp.net学习之 数据绑定控件--List数据绑定控件 List控件(如 CheckBoxList.DropDownList.ListBox 和 RadioButtonList 类)继承自L ...
- Redux基础
Redux 是一个状态容器 Redux 就像是作者自己的介绍,它不会为你提供任何的东西,它不会告诉你如何做路由,它只专注于应用程序状态,是一个 JavasSript 的状态容器,所有的状态的变化都是当 ...
- Codeforces Round #266 (Div. 2)-C,D
C - Number of Ways 直接暴力从前往后寻找.假设找到1/3sum的位置,那么标记++.找到2/3的位置,总数加上标记数. #include<stdio.h> #includ ...
- 一个数据表对象(NSManagedObject)加入排序
eg:数据库表对象 @interface Meditation : NSManagedObject @property (nonatomic, retain) NSString * order;//用 ...
- 我展示了视频采集前端vfe和camera,decode等交互驱动的体系结构
到现在都与处理器接触较多.更深入的驱动主要是前端视频采集.控制TI的DM64xx,DM3730.纪氏A31等待.他们发现,它们的使用的基本框架的是不一样的. 当然,典型camera例如ov系列,dec ...
- Cocos2d-X采用CCScrollView创建滚动视图
CCScrollView滚动视图可以让游戏有效果,并能够通过滚动视图切换游戏场景,滚动视图通常用来选择在游戏中的级别 实例1:使用CCScrollView创建一个简单的滚动视图 首先创建一个Scrol ...
- oracle_oracle中修改日期的显示格式
我的现在的日期格式是 ,要改成英文的需要输入一下命令: ALTER SESSION SET NLS_DATE_LANGUAGE=AMERICAN; 修改后变为: 同样也得若是英文要想 ...
- jquery跨域请求解决方案(我们寻找,我还没有添加验证)
http://www.3lian.com/edu/2014/02-10/127921.html 本篇文章仅仅要是对jquery ajax跨域解决方法(json方式)进行了介绍,须要的朋友能够过来參考下 ...