赞
踩
class A1 { public: virtual void P() const = 0; void print() const { std::cout << "A1\n"; }; }; class B1 : public A1 { public: void P() const override final { print(); } void print() const { std::cout << "B1\n"; } }; class B2 : public B1 { public: virtual void print() const { std::cout << "B2\n"; } }; class C1 : public B2 { public: void print() const { std::cout << "C1\n"; } }; int main() { B1 b1; B2 b2; C1 c1; A1* a1 = &b1; A1* a2 = &b2; A1* a3 = &c1; B1* b11 = &c1; B2* b22 = &c1; a1->P(); // 1 a2->P(); // 2 a3->P(); // 3 b11->P(); // 4 b22->P(); // 5 return 0; }
上述的输出全部都是"B1"。
原因是表达式1在执行名称查找时,首先去A1类中查找(因为a1
的类型显式类型是A1
指针),发现P()
是一个虚函数,因此就会从a1对象中的虚函数表中查找P()
的函数指针,发现此函数指针指向的是B1::P()
。然后B1::P()
中调用了print()
,因此直接在类B1
中查找print()
,如果找不到的话,编译器会继续到类B1
作用域的上层,即类A1
的作用域中查找print()
名称(所以如果你把B1::print()
注释掉的话,最终结果都是"A1"),编译器在B1
中找到了print()
,并发现它不是虚函数,因此不会去a1
对象的虚函数表中查找print()
,因此最终调用的就是B1::print()
;
表达式2和3在执行名称查找时,跟表达式1一样,因为P()
是虚函数,所以会从对应的对象的虚函数表中查找;
表达式4执行名称查找时,会先从B1
对象中查找名称P()
(因为b11
的显式类型是B1
指针),发现P()
是一个虚函数,因此会从对象b11
的虚函数表中查找P()
的地址。由于b11
对应的实际类型C1
并没有重载P()
,因此内存中b11
对象的虚函数表中P()
的指针仍然是B1::P()
,并没有被覆写。接着查找在B1::P()
中看到了名字print()
,并继续查找print()
,且查找过程同上面的分析一致,所以最终调用的也是B1::print()
;
表达式5看到P()
时会先到类B2
的作用域里面查找,发现找不到,因此就会扩大查找范围,到B2
类的基类B1
中查找,结果找到了。然后的分析过程就跟上面一样了,最终也是调用的B1::print()
。
如果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。