继承意味着有父类和子类。
1. 父类的对象、引用和指针只能调用父类中定义的成员函数。如果想让父类调用其某个成员函数时执行子类的操作,那么父类必须将该函数声明为virtual,并且子类中对该函数的定义必须与父类中的定义完全一样(返回值类型、函数名和函数形参列表完全相同,存在一个例外,就是“如果父类虚函数返回的是某个类的引用或指针,那么子类中该虚函数可以返回父类虚函数返回类型的派生类的引用或指针”,详细的请参考《C++ Primer中文版第4版》第15.2.3小节),而且还得是通过父类的引用或指针调用该函数。这个就是“多态”,详细的请参考相关书籍。(注:找到了一个例外,)
2. 子类的对象、引用和指针调用某个函数时,编译器会首先在子类的作用域中查找该名字。如找到,再进行常规类型检查(比如实参与形参能否对应上等,详细的请参考《C++Primer中文版第4版》第7.1.2小节),如果检查通过,则调用,否则,提示编译错误。如未找到,则到基类作用域中查找该名字。这样查找的原因是子类和父类各有自己的作用域,所以如果你想把父类中具有相同名字的所有函数引入到子类中,只需要在子类中利用using命令导入即可。比如父类为A,子类为B,A中存在多个名字为func的重载函数。如果你想在B中也拥有这些函数,则需要在B的定义中添加如下语句”using A::func;”。
另外,关于“同名屏蔽”,有如下规则:
1、如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)
2、如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
对于这2个规则,我的理解是:virtual关键字的影响力只是在“运行时”,即在运行时根据引用或者指针的动态类型来绑定相应的函数调用。而在编译时,其与普通函数一样,要接受子类和父类作用域的限制。如果子类中存在一个与父类中的某个虚函数同名但不同参的函数的话,那么该虚函数在子类中就被屏蔽掉了,也就是当子类的对象、引用或指针调用其父类中的该虚函数时,将会出现编译错误。
详细的请参考如下文章:
1. 《C++ Primer中文版第4版》第15.5小节
2. 《C++ using关键字作用总结》(http://blog.csdn.net/xiaogugood/article/details/21592529):该篇文章主要是对《C++Primer中文版第4版》中using用法的总结,大部分是在介绍“在子类中使用 using 声明引入基类成员名称”。
3. 《C++学习-继承中的作用域(10)》(http://blog.csdn.net/xiaogugood/article/details/21596275):这篇文章非常好。讲解了继承时,因为子类和父类作用域不同的问题所引发的成员访问问题,并且在每种情况下都给出一个实例,通俗易懂!