一般情况下,下面哪些操作会执行失败?
class A
{
public:
string a;
void f1()
{
printf("Hello World");
}
void f2()
{
a = "Hello World";
printf("%s",a.c_str());
}
virtual void f3()
{
printf("Hello World");
}
virtual void f4()
{
a = "Hello World";
printf("%s",a.c_str());
}
};
A、A *aptr = NULL; aptr->f1();
B、A *aptr = NULL; aptr->f2();
C、A *aptr = NULL; aptr->f3();
D、A *aptr = NULL; aptr->f4();
解析:
对于类成员函数而言,并不是一个对象对应一个单独的成员函数体,而是此类的所有对象共用这个成员函数体。 当程序被编译之后,此成员函数地址即已确定。而成员函数
之所以能把属于此类的各个对象的数据区别开, 就是靠这个this指针。函数体内所有对类数据成员的访问, 都会被转化为this->数据成员的方式。
而一个对象的this指针并不是对象本身的一部分,不会影响sizeof(“对象”)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。
函数参数入栈后,this指针的值也会入栈或者存入ecx寄存器。而this指针的值可以认为是pb的值,也就是->左边对象的值。传入this值的目的是为了操作对象里的数据,通过
类的声明,编译器可以确定对象内成员变量的相对于类对象起始地址的偏移,即相对this值的偏移。而成员函数调用时隐式传入的this值,编译器是不对this值进行检查,编译器
只是简单生成this+偏移操作对象的汇编代码,所以->左边对象的类型正确,编译器就会找到相应的成员函数,不管传入this值是否正确,只要this+偏移访问的地址是合法的,
os也不会抱怨,一旦this+偏移不合法,激活os的异常机制,程序才会宕了。
f1()没有用到成员变量,所以无需通过this指针访问,可以运行;
f2()用到成员变量,所以需要通过this指针+地址偏移找到成员变量,但this是NULL指针,会访问非法内存,所以不可运行;
f3()、f4()是虚函数,虚函数指针在对象构造完成后才能分配,所以不能运行;