C++语言用虚函数实现多态,比如,狼和鳄鱼都会咬(人),但是以不同的方式。实现代码大致如下,
class animal {
public:
virtual void bite();
};
class wolf: public animal {
public:
virtual void bite();
};
class crocodile: public animal {
public:
virtual void bite();
};
通过这样一个继承链和虚函数实现以后,可以狼和鳄鱼的对象可以以animal的面目出现在程序中,但仍然可以保持各自的个性bite()。这个就是多态。
如果把这个多态再封装一下, 把上文的class animal改名animal_imp,而狼和鳄鱼依然继承animal_imp,变成这样:
class animal {
private:
animal_imp *imp;
public:
animal(animal_imp *imp) :imp(imp){}
void bite() {imp->bite();}
};
现在,程序的其他部分引用这个改编的animal的时候,不需要考虑多态,而运行时实际上狼和鳄鱼还是保持了自己的个性bite()。
当animal类继续扩展,更多的公共属性出现在animal类中,这些属性跟 bite()无关,比如,
class animal {
private:
animal_imp *imp;
int h;
int w;
public:
animal(animal_imp *imp) :imp(imp){}
void bite() {imp->bite();}
int height();
int weight();
void grow();
};
出现差异的地方,即狼和鳄鱼的个性bite()被隐藏。复杂性得到了控制。多态出现的范围仅限于class animal。
由此可以推论,当多态的指针交给函数的时候,多态的范围就是函数;当多态的指针交给类成员的时候,多态的范围就是这个类;当多态的指针交给全局变量的时候,多态的范围就是全局;当多态的指针交给各个分散的代码段的时候,多态的范围就是各个分散的代码段。
作为一个实际例子,可以参看一下STL关于iostream的实现。在iostream类库中,filebuf作为stream_buf的派生类,通过重载为stream_buf填充和刷新buf的内容,供stream_buf使用。而含有多态内容的stream_buf指针,作为iostream类的构造函数参数,传递给iostream类,从而把多态的范围控制在iostream类。指针实际记录在basic_ios的_M_streambuf变量中。
class basic_ios: ios_base {
protected:
char_type _M_fill;
bool _M_fill_init;
basic_streambuf *_M_streambuf;
...
public:
bool operator!();
void _M_cache_locale(locale &__loc);
...
};
class basic_istream: basic_ios {
protected:
streamsize _M_gcount;
public:
explicit
basic_istream(__streambuf_type* __sb): _M_gcount(streamsize(0))
{ this->init(__sb); }
virtual ~basic_istream() { _M_gcount = streamsize(0); }
public:
__istream_type &operator>>(__ios_type &(*__pf)(__ios_type &));
__istream_type &operator>>(ios_base &(*__pf)(ios_base &));
__istream_type &operator>>(short &__n);
__istream_type &operator>>(unsigned short &__n);
__istream_type &operator>>(int &__n);
__istream_type &operator>>(unsigned int &__n);
__istream_type &operator>>(long &__n);
__istream_type &operator>>(unsigned long &__n);
__istream_type &operator>>(long long &__n);
__istream_type &operator>>(unsigned long long &__n);
__istream_type &operator>>(float &__f);
__istream_type &operator>>(double &__f);
__istream_type &operator>>(long double &__f);
__istream_type &operator>>(void *&__p);
__istream_type &ignore(streamsize __n);
__istream_type &ignore(streamsize __n, int_type __delim);
};
这里展示的istream作了大量的简化,无关部分已经省略。详细请看编译器的STL源码。