c++ primer 类中函数调用过程解析(虚函数与作用域) P550疑问解析

函数调用过程

即c++ primer 第五版中P549所谈,这里强调几点。
假定是p->mem() 或者obj.mem()

  • 首先确定静态类型,即p的类型。
  • 然后在这个静态类型中名字查找函数,即查找有没有mem。即 名字查找
  • 若没有则去静态类型(即p的类型)的直接基类中找,仍没有继续向基类中找。直到基类顶端。仍没有的话,就返回查找失败,发生错误。
  • 若找到了,接着类型检查,如果类型匹配就看这个函数是否是虚函数
  • 若类型不匹配,则直接返回类型匹配错误因为编译器名字查找,只要查到了,就停止名字查找了。
  • 若是虚函数,并且用指针或者引用调用,那么调用这个虚函数的哪个版本,依据是对象的动态类型
  • 否则,就常规调用,即用静态类型来调用。

P550疑问

主要对P550的bp2->fcn();bp2->f2();有疑问。可以看如下代码:

class Base{
friend class Pal;
public:
    virtual int fcn(){ std::cout << "基类的虚函数" << std::endl; return 1; }
private:
    char priv_mem;
protected:
    int prot_mem;
};

class D1 :public Base{
public:
    int fcn(int a){ std::cout << "D1类的有参数的fcn" << std::endl; return a; }
    virtual void f2(){ std::cout << "D1类的虚函数f2()" << std::endl; };//新的虚函数
};

class D2 :public D1{
public:
    int fcn(int a){ std::cout << "D2类的有参数的fcn" << std::endl; return a; };
    int fcn(){ std::cout << "D2类的无参数的fcn" << std::endl; return 1; };
    void f2(){ std::cout << "D2的f2()" << std::endl; };
};

int main(int argc, const char *argv[])
{
    Base bobj; D1 d1obj; D2 d2obj;
    Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
    bp1->fcn();
    bp2->fcn();
    bp3->fcn();
    //bp2->f2(); //错误 Base没有名为f2的成员
    system("pause");
    return 0;
}

1.首先解释bp2->fcn()为什么调用的是基类的那个虚函数。
根据函数调用规则,先在静态类型即Base类中找fcn,名字查找,找到了。接着进行类型检查,确实是无参类型,再看是否是虚函数,是的,那么依据动态类型来调用。动态类型是D1类,即调用D1::fcn();。但是D1类没有覆盖fcn()虚函数,是直接继承的,故调用的仍是Base::fcn()

2.再看bp2->f2();依然先名字查找,静态类型为Base,没有f2,故报错Base类无成员f2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章