如下一个abstract base class声明:
class Abstract_base
{
public:
virtual ~Abstract_base() = 0;
virtual void interface() const = 0;
virtual const char*
mumble() const {return _mumble;}
protected:
char* _mumble;
};
虽然这个class被设计为一个抽象的base class(其中有pure virtual function,使得Abstract_base不可能拥有实例),但它仍然需要一个显示的构造函数来初始化其data member _memble。如果没有这个初始化操作,derive class的局部成员_memble将无法决定初值,例如:
class Concrete_derived : public Abstract_base
{
public:
Concrete_derived();
...
};
void foo()
{
//Abstract_base::_mumble未初始化
Concrete_derived trouble;
//...
}
也许Abstract_base 的设计者意图让其每一个derived class 提供_mumble的初值。如果这样,derived class唯一要求就是Abstract_base必须提供带有唯一参数protected constructor:
Abstract_base::Abstract_base(char* mumble_value = 0)
:_mumble(mumble_value){}
一般而言,class的data member应该被初始化,并且只能在constructor中或在class的其他member functions中指定初值。其他操作破坏封装,使得class的维护和修改更加困难。
也可能说设计者错误并不在于为提供了explicit constructor,而是不应该在抽象的base class中声明data members(把interface和implementation分离),然而将“共享数据”抽象出来放在base class中,也是一红正确的设计。
纯虚函数的存在(Presence of a Pure Virtual Function)
一个pure virtual function可以被定义和调用,只能静态的调用,不能经由虚拟机制调用:
inline void
Abstract_base:: interface() const
{
function
//...
}
inline void
Concrete_derived::interface() const
{
//静态调用
//调用一个pure virtual function
Abstract_base::interface();
}
要不要这么做,全由class设计者决定。唯一的例外就是pure virtual destructor必须定义:每一个derived class destructor会被编译器加以扩张,以静态调用的方式调用其“每一个virtual base class”以及“上一层base class"的destructor,因此只要缺乏任何一个base class destructor定义,就会导致链接失败。
一个好的替代方案就是:不要把virtual destructor声明为pure。
虚拟规格的存在(Presence of a Virtual Specification)
把Abstract_base::mumble()设计为一个virtual function是一个糟糕的选择,因为其函数定义内容并不与类型有关,因为几乎不会被后继的derived class 改写。此外,由于它的non-virtual 函数是个inline函数,如果常常被调用的话,效率上的报应不可谓不轻。
一般而言,把所有的成员都声明成为virtual function,然后再靠编译器的优化操作把非必要的virtual function去除,并不是好的设计理念。
虚拟规格中的const存在
决定一个virtual function是否需要const,似乎是件琐碎的事情。当你真正对一个abstract base class时,却不容易决定。做这件事情:意味着预期subclass实例可能被无穷次数的使用,不把函数声明成const,以为此函数不能够获得一个const reference或const pointer。声明一个const,然后才发现derived instance必须修改某一个data member。最简单的做法就是不声明const。
重新考虑class的声明
由前面讨论,重新定义Abstract_base如下,才是比较合适的一种设计:
class Abstract_base
{
public:
virtual ~Abstract_base(); //不再是pure
virtual void interface() const = 0; //不再是const
const char*
mumble() const {return _mumble;} //不再是virtual
protected:
Abstract_base(char* pc = 0); //新增一个带唯一参数的constructor
char* _mumble;
};