this指针简单来说:通过对象来调用一个非静态成员函数,那个对象的地址就是this。this是隐含在每一个非静态成员函数的内部的指针常量。
1 class CDocument 2 { 3 public: 4 void onFileOpen() 5 { 6 7 first(); 8 second(); 9 Serialize();//动态变化的部分 10 last(); 11 12 } 13 virtual ~CDocument() {} 14 protected: 15 virtual void Serialize() = 0; 16 void first(); 17 void second(); 18 void last(); 19 }; 20 21 void CDocument::first() { cout << "dialog..." << endl; } 22 void CDocument::second() { cout << "check file..." << endl; } 23 void CDocument::last() { cout << "close file..." << endl; } 24 //application 25 class CMyDoc :public CDocument 26 { 27 public: 28 void Serialize() //子类重写 29 { 30 cout << "CMyDoc::serialize..." << endl; 31 } 32 }; 33 int main() 34 { 35 CMyDoc mydoc; 36 mydoc.onFileOpen(); //子类对象调用父类函数 37 }
以上第36行可以理解为:mydoc.onFileOpen(&mydoc),this指向这个对象的地址,接着就把this指针传递给 了onFileOpen()。
1 void CDocument::onFileOpen() 2 { 3 4 this->first(); 5 this->second(); 6 this-> Serialize(); //动态绑定 7 this->last(); 8 9 }
由于this是一个向上转型后的指针,父类指针指向子类对象,并且在第6行调用虚函数,于是编译器就把第6行转变成(*this->vptr[n])(this),所以会调用子类的虚函数。
这里的vptr是一个虚函数指针,指向虚函数表,表中是类的虚函数地址。当父类写了一个虚函数时,父类内部就多了一个虚函数指针(vptr),这个指针指向它的虚函数表,表中存放的是函数的入口地址(比如serialize()),当子类继承父类时,会把父类中的虚函数指针继承下来,指向子类的虚函数表。(此时虚函数表中的地址和父类的虚函数地址一样)当子类重写了父类的虚函数时,子类就会把虚函数表中函数地址替换成自己重写的虚函数地址。当发生动态绑定(三个条件:1、是指针调用2、是一个向上转型的指针3、调用虚函数),编译器就会把第6行转变成(*this->vptr[n])(this),调用子类重写的虚函数。