首页 > 试题广场 >

头文件已经正常包含,以下代码在VS IDE上编译和运行结果是

[单选题]
头文件已经正常包含,以下代码在VS IDE上编译和运行结果是
class A{
    public:
	void test(){printf("test A");}
};
int main()
{
    A *pA = NULL;
    pA->test();
    return 0;
}

  • 编译出错
  • 程序运行奔溃
  • 输出"test A"
  • 输出乱码
第一,这道题目应该是写法有点问题,应该是这样的(注意类后面加了分号,test后面加了括号)
#include<iostream>
using namespace std;
class A{
public:
	void test()
	{ printf("test A"); }
};
int main(){
	A* pA = NULL;
	pA->test();
	return 0;
}
其实这个是可以正常运行的
原因如下:

因为对于非虚成员函数,C++这门语言是静态绑定的。这也是C++语言和其它语言Java, Python的一个显著区别。以此下面的语句为例:
pA->test();
这语句的意图是:调用对象 pA test 成员函数。如果这句话在Java或Python等动态绑定的语言之中,编译器生成的代码大概是:
找到 pA test 成员函数,调用它。(注意,这里的找到是程序运行的时候才找的,这也是所谓动态绑定的含义:运行时才绑定这个函数名与其对应的实际代码。有些地方也称这种机制为迟绑定,晚绑定。)
但是对于C++。为了保证程序的运行时效率,C++的设计者认为凡是编译时能确定的事情,就不要拖到运行时再查找了。所以C++的编译器看到这句话会这么干:
1:查找 pA 的类型,发现它有一个非虚的成员函数叫 test 。(编译器干的)
2:找到了,在这里生成一个函数调用,直接调A:: test ( pA )。
所以到了运行时,由于 test ()函数里面并没有任何需要解引用 pA 指针的代码,所以真实情况下也不会引发segment fault。这里对成员函数的解析,和查找其对应的代码的工作都是在编译阶段完成而非运行时完成的,这就是所谓的静态绑定,也叫早绑定。
正确理解C++的静态绑定可以理解一些特殊情况下C++的行为。
发表于 2016-03-23 21:16:51 回复(16)
C应该是正确的。
根据<<深度探索c++对象模型>>里面说到的,普通成员函数在编译器实现时,大致经历一下转化过程:
1.改写函数的签名以安插一个额外的参数 - this指针
2. 将每一个对非静态成员数据成员的存取操作改为经由this指针来存取。
3.将成员函数重写成外部函数,函数名称经过“mangling"处理,使其在程序中有唯一的名字。
(重写成外部函数,是希望在实现成员函数的时候,使其效率接近普通非成员函数,尽可能避免带来额外开销)
------------------------
A*pA=null;
pA->test(); //当调用成员函数时,只是将实参null传给this指针(对应1.)
test成员函数中并无任何需要通过this指针访问的数据成员(对应2.),因此没有带来任何影响
编辑于 2016-04-02 23:55:32 回复(1)
这道题目应该选C,能够正常运行。
test函数作为非虚函数,在编译时就确定了。即使pA为null,但是已经声明了类型,就知道pA有个test函数,且test函数里没有用到成员变量,单单一个打印语句是可以运行成功的。
自己去vs敲好运行下就知道了。

发表于 2016-03-28 17:25:16 回复(0)
空对象指针不能访问数据成员(非静态的),可以访问函数(非虚函数),因为数据成员要分配内存才能访问,而函数是不需要的,虚函数通过虚函数表指针访问
编辑于 2019-06-07 11:45:42 回复(0)
把这道题作对可真不容易
发表于 2016-08-02 13:44:01 回复(0)
c++编译过程不会检查空指针
所以,这种空指针问题一般是在运行时奔溃
发表于 2016-03-23 19:31:45 回复(0)
补充一下,本题中NULL指针调用成员函数的时候成员函数中没有成员变量,如果访问此对象的成员函数,则程序崩溃,因为this指针是NULL
发表于 2017-10-09 16:25:13 回复(1)
参考@leobuzhi的回答,做个笔记。
运行到A* pA = NULL时,发现pA是A类型。由于test()是非静态成员函数,因此不是动态绑定,而是编译时已经确定,即知道A有一个test()函数,然后在pA->test()时直接调用它;又由于test()内部并没有用到解引用pA指针的代码,因此即使pA=NULL,也能正常运行而不报错。
发表于 2016-08-02 16:27:55 回复(0)
应该选择C 输出“test A"。 
主要原因是C++的类自带this指针。每个类成员函数都默认带有一个this指针参数,当对象调用方法时,this指针能够访问类的数据。
classA{
    public:
    voidtest(){printf("test A");}
    //其实早期的编译器是这样处理的:void test(A *this){printf("test A");}
};
intmain(){
    A*pA=null;
    pA->test();
//同理在编译器中也应该是   test(p);当p为空,类中的方法自动使用缺省参数,也就是this指针。
}
编辑于 2016-03-28 00:46:22 回复(0)
前置知识:
在C++中,没有类的成员函数中都默认添加了一个this指针,这个this指针指向被调用的对象。
如:
Class A
{
public:
     A(int a){this->a = a;}
     void GetA1(){cout << "void GetA1()" << endl;}
     void GetA2(){cout << this->a << endl;}
public:
    int a;
}
A* p = NULL;
p->GetA1();//ok
p->GetA2();//err
以上两个成员函数会被编译器处理,在每个成员函数中添加this指针形参
GetA1(A *const this){cout << "void GetA1()" << endl;}
GetA1(A *const this){cout << this->a << endl;}
为什么两个调用一个成功,一个失败呢?
由于this指向被调用的对象,也就是p。因为GetA1中没有使用this指针访问成员,就不会出现非法访问的问题。而GetA2中this->a访问成员变量a,也就是NULL访问a,非法访问,所以失败。
总结:
当定义一个空指针的对象指针,去访问该成员函数时。即:this指向空指针的对象指针

1 如果成员函数中没有用到this指针,可以用空指针调用该成员函数

2 如果成员函数中用到了this,那么需要对这个this加判断语句,防止空指针解引用

发表于 2023-04-29 21:21:09 回复(0)
实践出真知,以下是在linux g++上面测试的结果。

发表于 2020-06-28 20:14:19 回复(0)
虽然指针 pA 被赋值为 NULL,但在调用 pA->test() 时,实际上并不会使用指针所指向的对象,而只是调用了对象的成员函数。在调用非虚拟函数时,编译器会将成员函数的调用转换为对函数的静态绑定调用(Static Binding),此时并不需要用到对象的地址,因此不会出现访问空指针所引发的异常。
发表于 2023-10-20 21:34:06 回复(0)
无虚函数静态绑定,在编译的时候确定
发表于 2016-06-29 22:24:05 回复(0)
对于非虚成员函数,C++是静态绑定的,所以有声明A *pA=NULL时,已经将指针绑定到类A了,所以调用时会正常输出。
发表于 2016-05-21 16:09:02 回复(0)
段错误,访问未初始化的内存区域
发表于 2016-03-24 15:44:23 回复(0)
疑惑点:为什么能使用空指针调用函数,不应该报指针错误么
发表于 2022-06-15 14:32:56 回复(0)
为什么我用的vs2013,编译就不通过,直接底下就划红线了?
发表于 2016-07-14 16:03:23 回复(2)
但是为什么用visual stdio2012运行答案是C
发表于 2016-03-25 20:04:25 回复(1)
等效于该代码:
struct A{ }; void test(A *pA) {         printf("test A");  } int main(){ A* pA = NULL; test(pA); return 0; }

发表于 2024-05-13 20:24:47 回复(0)
class不是c++的概念吗?
发表于 2022-06-14 20:54:20 回复(0)