模板方法模式(Template Method Pattern): 通过一个公共的、非虚拟的成员函数调用一个受保护的虚拟函数。文章中的Mountie类的read和write函数可能就是调用了do_read和do_write的受保护虚拟函数,这是模板方法模式的经典示例。
行为设计模式的一种,主要用于定义算法的骨架,而将一些步骤的具体实现推迟到子类中。这样,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
核心:public非虚函数定义接口,protected虚函数定义实现。
class Mountie{
public://定义算法的骨架,约定了算法接口
void read(std::istream &is) {
do_read(is);
}
void write(std::ostream &os) const {
os << classID() << std::endl;
do_write(os);
}
virtual ~Mountie() {}
protected://强制派生类给出具体算法实现
virtual void do_read(std::istream &is) = 0;
virtual void do_write(std::ostream &os) const = 0;
virtual std::string classID() const = 0;
};
class TextMountie : public Mountie{
protected:
void do_read(std::istream &is) override {...}
void do_write(std::ostream &os) const override{...}
std::string classID() const override {
return "TextMountie";
}
};
私有虚拟函数:文章描述了对私有虚拟函数的困惑和解释。尽管一个虚拟函数被声明为私有,继承的子类仍然可以覆盖它。这个功能使得基类能够强制子类为某个功能提供实现,而不直接允许子类或其他类调用该功能。
存取权限与虚拟性:存取权限(例如公有、保护、私有)和函数是否为虚拟的是两个独立的概念。一个函数是否为虚拟的决定了它是静态绑定还是动态绑定,而存取权限决定了哪些类可以直接访问该函数。
类设计与可扩展性:公共虚拟函数可能在后期的类设计中导致问题,因为它们难以进行修改而不影响继承的子类。文章建议:像数据成员一样对待虚拟函数,使其为私有,除非有明确的设计需求表明需要放宽其访问级别。如果需要修改或增强虚拟函数的行为,采用模板方法模式更为方便。
C++的语言"感觉":除了语法和规则外,理解C++的某些习惯用法和“感觉”也很重要。例如,一个类如果有一个虚拟的析构函数,则暗示该类设计为基类,并可能被继承。
文章强调了在设计C++类时要考虑其未来的扩展性以及如何通过虚拟函数和存取权限来实现这种扩展性。