-> 空对象上的运算符
-> operator on null objects
根据C++标准,这样做是完全可以接受的:
class P
{
void Method() {}
};
...
P* p = NULL;
p->Method();
然而,有一个小小的变化:
class P
{
virtual void Method() {}
};
...
P* p = NULL;
p->Method();
使用Visual Studio 2005编译时会产生访问冲突。
据我所知,这是由微软编译器实现中的一些怪癖引起的,而不是我完全没有能力进行更改,所以问题是:
1) 这种行为在最近版本的VS中持续存在吗?
2) 我不知道有没有编译器设置可以防止这种访问违规?
根据C++标准,这样做是完全可以接受的
不,不是
根据C++标准,取消引用NULL
指针是未定义的行为[#1]
但是,如果您不访问非虚拟成员函数内的任何成员,它很可能在每个实现中都有效,因为对于非虚拟成员功能,this
只需要在访问this
的成员时取消通知,因为函数内没有被访问的成员,因此会产生结果
然而,仅仅因为可观察的行为是好的,并不意味着程序是良好的correct它仍然是不成形的
然而,这是一个无效的程序。
第二个版本崩溃是因为在访问虚拟成员函数时,即使在调用适当的成员函数时也需要取消引用this
指针,即使该成员函数中没有访问的成员也是如此。
一本好书:
虚拟和非虚拟成员函数的调用方式有什么区别?
[#1]参考:
C++03标准:§1.9/4
某些其他操作在本国际标准中被描述为未定义(例如,取消引用
null
指针的效果)。【注:本国际标准对包含未定义行为的程序的行为没有任何要求。】
正如AI所说。。。我甚至会解释为什么:在许多C++实现中,this
指针只是作为方法的第一个"隐藏"参数传递的。所以你所看到的
void Method() {}
真的是
void Method(P* this) {}
但对于虚拟方法来说,它更为复杂。运行时需要访问指针以找到"真实"类型的P*,才能调用该方法的"正确"虚拟实现。所以它有点像
p->virtualTable->Method(p);
所以总是使用p。
首先,两者都不会编译,因为您已经将Method
定义为私有。
假设您将Method
公开,那么在这两种情况下都会出现未定义的行为。基于典型的实现,大多数编译器将允许第一个"工作"(对于相当松散的工作定义),而第二个基本上总是失败。
这是因为非虚拟成员函数基本上是接收额外参数的正常函数。在该函数中,关键字this
指的是该额外参数,该参数是指向调用该函数的类实例的指针。如果您通过空指针调用成员函数,这主要意味着函数this
内部将是一个空指针。只要函数中没有任何内容试图取消引用this
,就很有可能看到任何明显的副作用。
然而,虚拟函数基本上是通过指针调用的函数。在一个典型的实现中,任何具有一个或多个虚拟函数的类(无论是直接在该类中定义的,还是从基类继承的)都将具有vtable。该类的每个实例(即,每个对象)都将包含指向其类的vtable的指针。当您尝试通过指针调用虚拟函数时,编译器将生成以下代码:
- 取消引用该指针
- 从该对象的正确偏移量获取vtable指针
- 取消引用vtable指针以获取类的vtable
- 查看vtable中的适当偏移量,以获取指向要调用的函数的指针
- 调用该函数
给定一个空指针,该过程的第一步将中断。
我要注意的是,这实际上适用于所有C++编译器。VC++在这方面远非独一无二。恰恰相反——虽然理论上编译器可以实现与此不同的虚拟函数(例如),但事实是,我所知道的每个编译器对于您发布的代码基本上都是相同的。事实上,在给定相同代码的情况下,所有C++编译器都会表现出类似的行为——实现中的主要差异大多是理论上的可能性,而不是你在实践中可能遇到的。
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 为什么常量词在重载运算符中不与 ostream 对象一起使用<<?
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 运算符重载 += 添加新对象
- 如何用 2 个对象过度引导运算符
- C++内联运算符重载中,请参阅当前对象
- 使用运算符"="在C++中用值初始化对象
- C++运算符重载做双 * 对象
- 如何在自定义对象的<<运算符中添加自定义前缀
- 尝试重载输出运算符时,我无法遍历对象向量
- 我重载了 << 和 = 运算符。为什么当我将一个对象分配给另一个对象并尝试打印它时,我会被打印出来?
- 在之后仍需要使用源对象时调用父移动分配运算符
- 错误:三元运算符无法在对象中正常工作"cout"
- 为什么我在声明对象数组时不能使用 -> 运算符?
- 无法使用迭代器查找类对象。(二进制 '==': 'userInfo' 不定义此运算符)
- 重载加法运算符(使用函数向对象添加字符串)
- 临时对象上的运算符重载
- 如何使用运算符+重载函数正确返回对象?
- 如何分配适合容纳 T 类型对象的缓冲区(可能过度对齐、可能有运算符 new 等)
- 重载运算符 [] 用于从对象数组中给出特定索引