基类用一个public nonvirtual 成员函数访问protected virtual成员函数,子类在需要的时候可以选择Overriding那个protected virtual成员函数,如果是个pure protected virtual成员函数,那就必须Overriding它。
1.AbstractClass(抽象类):定义一到多个抽象方法,至少应该是virtual方法。如果AbstractClass负责实现一个通用版本的算法,各子类对该方法进行进一步细化,则只需定义成virtual方法,具体的子类将重定义它们以实现一个算法;而且还实现一个模板方法,来定义一个算法的骨架。
该模板方法不仅调用前面的抽象方法,也可以调用其他的操作。
各抽象方法往往被定义成protected(保护)成员,以保证它们只被模板方法调用,而TemplateMethod往往被定义成public非虚成员函数。
2.ConcreteClass(具体类):实现父类中的抽象方法以完成算法中与特定子类相关的步骤。这里的关键是基类中的TemplateMethod方法,因为正是它定义了对各子类对象适用的通用的处理逻辑。
空泛的理论总是令人乏味,给个例子:
///
class Mountie
{
public:
void read( std::istream & );
void write( std::ostream & ) const;
virtual ~Mountie();
protected:
virtual void do_read( std::istream & );
virtual void do_write( std::ostream & ) const; //派生类对象需要调用这两个函数的实现来读写其中的基类对象
private:
virtual std::string classID() const = 0;
//在该程序中,classID()是一个实现细节,用来在保存对象时指示具象类的类型,派生类必须覆盖它,所以必须是纯虚的。但是既然是实现细节,就应该设为private的。
}
void Mountie::write(std::ostream &Dudley) const
{
Dudley << classID() << std::endl;
do_write(Dudley);
}
///
似乎有些难以理解,换一个:
///
class Sort
{
// Shell sort //
public:
void doIt( int v[], int n )
//基本的排序逻辑在基类Sort中实现
{
for (int g = n/2; g > 0; g /= 2)
for (int i = g; i < n; i++)
for (int j = i-g; j >= 0; j -= g)
if (needSwap(v[j], v[j+g]))
doSwap(v[j], v[j+g]);
}
private:
virtual int needSwap(int,int) = 0;
void doSwap(int& a,int& b)
{
int t = a; a = b; b = t;
}
};
class SortUp : public Sort
//但具体的排序方法(升序还是降序)由子类决定
{
int needSwap(int a, int b)
{
return (a > b);
}
};
///
///
最后给一个例子:Template Method使得基类控制了函数的调用顺序(执行流程),子类只负责某个步骤的实现(具体要看是虚还是纯虚)。
class App
{
public:
virtual ~App();
void startup()
{ // Template Method
initialize();
if( !validate() )
altInit();
}
protected:
virtual bool validate() const = 0;
virtual void altInit();
private:
void initialize();
};
class MyApp : public App
{
public:
//...
private:
bool validate() const;
void altInit();
};