我们把一个仅仅含有纯虚函数的类称为接口,我们也好像已经习惯了将这个接口中的所有纯虚函数全声明为public,而且按照这样的设计,一切都工作得不错。比如COM正是这样做的,它的接口中几乎不会存在private的纯虚函数。那么,让我们想一想,纯虚函数或者虚函数可以为private吗?如果这种方式是可行的,那么什么时候可以将(纯)虚函数设为private了?这些都是本文将要讨论的主题。一起来看看。
一、访问限定符与继承
如果基类隐式(间接)向子类暴露了私有成员,那么从某种意义上讲,该私有成员对于子类是可见的。
任何一本讲C++基础的课本上都详细地介绍了访问限定符与继承的关系,在这里就不重复了,但是,课本上的东西并不全,不信?那么请先看看下面的例子:
#include <string> class Base protected: public: virtual ~Base() class DerivedA : public Base protected: cout<<"this is DerivedA doWork !"<<endl ; |
以上的代码声明了一个基类和一个子类,不过比较奇特的是基类的提供的公共接口是非虚的,而这个非虚的公共接口却调用了一个非虚的私有函数和一个虚拟的保护函数。接着,子类重定义了这两个函数。那么下面的调用会输出什么了?
Base* bp = new DerivedA(); bp->work(); delete bp ; |
以下是输出的结果:
this class id is Base this is DerivedA doWork! |
怎么回事?为什么不是
this class id is DerivedA this is DerivedA doWork! |
子类的classID()不是将基类的classID()覆盖了么?我们来分析一下,基类中的公共的work()成员函数调用了私有的classID()成员函数,根据输出的结果来看,在子类中定义的classID方法并没有覆盖基类的同名方法,为什么呢?难道是因为classID是private导致的?那好,我们将classID函数改为public再次运行,我们期望的结果出现了吗?呵呵,很抱歉,没有,希望再次破灭了,为什么会这样?这主要涉及的原因是:普通函数的调用是在编译期确定的,当work函数一看到所调用的classID是非虚的,就会毫无疑问地去直接使用基类的classID。这一切与Base类是否会被继承没有任何关系,跟Base类被继承后子类会否再次定义classID就更没有关系了。