MFC第1天--跟踪代码要抓重点--切记切记--侯杰复习C++

最重要的类:CObject和CCmdTarget

侯杰MFC  C++复习:

三个结论:
1.如果你以一个“基类指针”指向“派生类的对象”,那么该指针只能够调用基类所定义的函数。
2如果你以一个“派生类的指针”指向“基类的对象”,那么你必须先做明显的类型转换,这种做法很危险,不符合真实生活经验,在程序设计上也会给程序员带来困惑
3.如果基类和派生类都定义了  相同名称的成员函数  那么通过对象指针调用成员函数时,到底调用到那一个函数,必须视该指针的原始类型而定,而不是视指针实际所指的对象的类型而定。这与第一点意义相同。

指向不同类型的对象,调用不同版本的同名的成员函数。这种性质就是多态。靠虚函数来完成。
虚函数正式为“    1.如果你以一个“基类指针”指向“派生类的对象”,那么该指针只能够调用基类所定义的函数。   ”这条规则反其道而行之的设计。
MFC中有两个十分十分重要的虚函数:与document有关的Serialize函数  和 与view有关的OnDraw函数。你应该在自己的CMyDoc  和 CMyView中改写这两个虚函数。
我们以相同的指令调用不同的函数,这种性质称为多态。
虚函数是了解多态以及动态绑定的关键,同时他也是了解如何使用MFC的关键
如果期望派生类重新定义一个成员函数,那么应该在基类中吧此函数设为virtual
既然抽象类中的虚函数不打算被调用,我们就不应该定义它但是又必须 保留一块空间给它,于是C++提供了所谓的纯虚函数:
class CShape
{
    public:
    virtual  void display()=0;    //注意“= 0”   在函数声明之后加上=0;即可。
};
纯虚函数不需要定义其实际操作,它的存在只是为了在派生类中被重新定义,只是为了提供一个多态接口,只要拥有纯虚函数的类,就是一个抽象类,以区别所谓的具体类,他不能够被实例化的,也就是说,你不能根据他产生一个对象。但是我们可以拥有指向抽象类的指针,以便于操作抽象类的各个派生类。如果CCircle继承了CShape之后,如果没有改写CShape中的纯虚函数那么CCircle本身也就成为一个纯虚函数的类,于是他也是一个抽象类。虚函数派生下去仍为虚函数,而且可以省略virtual关键字

虚表:
如果能够了解C++编译器对虚函数的实现方式,我们就能够知道为什么虚函数可以做到动态绑定。
为了达到动态绑定(后期绑定)的目的,C++编译器通过某个表格在执行  间接 调用实际上欲绑定的函数,这样的表格称为  虚表vtable/虚函数表  每一个内涵虚函数的类,编译器都会为他做出一个虚函数表,表中的每一个元素都指向一个虚函数的地址,此外  编译器当然也会为类加上一项成员变量,是一个指向该函数表的指针vptr:


每一个派生类的对象,都有一个vptr当我们通过这个对象调用虚函数时,事实上是通过vptr找到虚函数表再找出虚函数的真正地址。
奥妙在于这个虚函数表以及这种间接调用方式,虚函数表的内容是依据类中的虚函数的声明次序,一一填入函数指针。派生类会继承基类的虚函数表 以及所有其他可以继承的成员。当我们在派生类中改写虚函数时,虚函数表就收到了影响:表中所有元素指向的函数地址将不再是基类的函数地址,而是派生类的函数地址,看下面的例子:


动态绑定机制,在执行期间,根据虚函数表,做出了正确的选择










posted @ 2016-03-20 15:39  hungryvampire  阅读(753)  评论(0编辑  收藏  举报