大家都觉得很自然,但是没有注意到一个小插曲,就是这个foo()触发的隐藏机制: 派生类的foo()由于函数名,参数与基类都相同,然而又没有virtual修饰,因此不可避免地会触发隐藏。
(一旦有virtual修饰就成覆盖了!搞不清楚隐藏何时触发的同学请百度:重载、覆盖、隐藏的区别)
问题是,看到有同学问: 为什么此处触发隐藏了,p和ptr在调用foo()的时候仍然调用基类的,不是被隐藏了么???
这么问的原因是,很多同学知道了有隐藏这么回事,但是不清楚隐藏触发后会发生什么。 隐藏机制触发之后,指针的调用取决于指针的类型。如果定义的是派生类指针,则该基类成员不可见(隐藏),但是若为基类指针,该基类成员仍然是可见的啊!因为此处的p和ptr均为基类指针,只是分别指向了基类和派生类对象,所以调用foo()的时候仍然是基类的成员。
但是如果定义个派生类指针pb,如下:
B *pb=&b;
pb->foo();
这时只会调用派生类的foo(),虽然B继承自A,但是基类的foo()会被隐藏。
这样看起来似乎莫名其妙,因为你想当然地认为派生类的指针肯定调用自己的成员啊,隐藏存在的意义是什么?就像此题,不用考虑它我也能做对!
但是一旦foo()里有参数的时候,你就会大吃一惊!
假设A中为void foo(float a),B中为void foo(int a):
做如下调用:
B *pb=&b;
pb->foo(3.14);
到底会调用谁?你可能会想: 首先foo()成 员不是虚函数,但是B继承A,B中有两个foo(),调用foo(3.14)时根据参数类型应该匹配基类的void foo(float)成员。
然而并不是!
因为触发了隐藏机制,基类的void foo(float)会被隐藏,所以即使你调用foo(3.14)仍然只会调用派生类的void foo(int)成员。
你的惊讶正好解释了隐藏机制存在的意义。
(PS:牛客网上C/C++专项训练上有专门一道题考察这种情况,当时解释里提出隐藏机制时大多数人也是一脸懵逼)
总结:
1.判断要点:如果不是重载也不是覆盖,派生类和基类中一旦出现同名函数,一定触发隐藏机制(这是个简便判断技巧,你可以考虑除去重载和覆盖的任何同名函数情况,一定满足隐藏机制触发的两条规则)。
2.隐藏触发的结果:指针对成员的函数调用取决于指针类型。
若本身是基类指针(不管指向基类还是派生类)则仍然调用基类成员(不会牵扯到派生类,此处是隐藏,和多态没关系,按第1点已说明隐藏的触发可以首先排除覆盖,也就是多态问题);
若本身是派生类指针,这时你就会看到隐藏的威力!此时不是简单地继承基类的成员,然后根据参数匹配调用,而是隐藏基类成员,只会调用派生类成员。