在孙鑫老师的论坛中有答案,但是对答案有些疑惑,于是注册了一个账号想发表一下问题,可是新注册用户在1440分钟以内不能发言,结果过了一天还是没能提个问题,真是郁闷之极啊!于是先在这里写我的问题。
在第三讲中,孙老师说基类中使用的this指针在派生类生成的对象当中,是指向派生类对象的,可是我按他说的方法去测试一下,结果是指向基类对象,这是为什么?
class Point
{
public:
void output() {cout<<"调用了基类的output()函数.";}
void cjp() { this->output();}
};
class test:public Point
{
public:
void output () { cout<<"调用了派生类的output函数。"; }
};
void main()
{
test tt;
tt.cjp();
}//endof main()
按孙老师的意思应该输出:“调用了派生类的output函数”,但是结果是 "调用了基类的output()函数."
说明this指针指向的是基类的对象,这与孙老师的意思相反,
我的问题出在那里? 是我对他的意思理解有误?
下面是孙老师在论坛上的回答:
帖子位置 http://www.sunxin.org/bbs/dispbbs.asp?boardID=2&ID=10641&page=1
VC视频第三课this指针说明
我在论坛的VC教学视频版面发了帖子,是模拟MFC类库的例子写的,主要是说明在基类的构造函数中保存的this指针是指向子类的,我们在看一下这个例子:
例1- 3
#include <iostream.h>
class base;
base * pbase;
class base
{
public:
base()
{
pbase=this;
}
virtual void fn()
{
cout<<"base"<<endl;
}
};
class derived:public base
{
void fn()
{
cout<<"derived"<<endl;
}
};
derived aa;
void main()
{
pbase->fn();
}
我在base类的构造函数中将this指针保存到pbase全局变量中。在定义全局对象aa,即调用derived aa;时,要调用基类的构造函数,先构造基类的部分,然后是子类的部分,由这两部分拼接出完整的对象aa。这个this指针指向的当然也就是aa对象,那么我们在main()函数中利用pbase调用fn(),因为pbase实际指向的是aa对象,而aa对象内部的虚表指针指向的是自身的虚表,最终调用的当然是derived类中的fn()函数。
在这个例子中,由于我的疏忽,在derived类中声明fn()函数时,忘了加public关键字,导致声明为了private(默认为private),但通过前面我们所讲述的虚函数调用机制,我们也就明白了这个地方并不影响它输出正确的结果。不知道这算不算C++的一个Bug,因为虚函数的调用是在运行时确定调用哪一个函数,所以编译器在编译时,并不知道pbase指向的是aa对象,所以导致这个奇怪现象的发生。如果你直接用aa对象去调用,由于对象类型是确定的(注意aa是对象变量,不是指针变量),编译器往往会采用早期绑定,在编译时确定调用的函数,于是就会发现fn()是私有的,不能直接调用。:)
许多学员在写这个例子时,直接在基类的构造函数中调用虚函数,前面已经说了,在调用基类的构造函数时,编译器只“看到了”父类,并不知道后面是否后还有继承者,它只是初始化父类对象的虚表指针,让该虚表指针指向父类的虚表,所以你看到结果当然不正确。只有在子类的构造函数调用完毕后,整个虚表才构建完毕,此时才能真正应用C++的多态性。换句话说,我们不要在构造函数中去调用虚函数,当然如果你只是想调用本类的函数,也无所谓。
我的问题:
如果说this指针指向派生类的对象,那么是不是意味着基类里使用的this指针与派生类里使用的this指针完全等同?
但事实上,要使基类里的this指针调用到派生类的fn()函数,基类中的fn()函数必须是虚函数,否则会像我的试验中一样,调用到基类的fn()函数。在我的试验中,如果把基类Point中的output声明为虚函数,那么cjp()调用的结果会是我们想要的结果:即调用派生类的output()函数。
如果基类里使用的this指针与派生类里使用的this指针不是一回事,那么孙老师为什么要提出“说基类中使用的this指针在派生类生成的对象当中”?意义何在?