这是有一点需要注意,对于一个函数pure virtual函数的抽象基类是无法实例化的,无论是通过new,还是直接声明对象,编译器都会报错。
但是,对于一个纯虚函数,我们是可以给这个纯虚函数提供相应的函数定义的,并且也可以执行成功,可以通过作用域来指定需要执行的函数。
这种情况下,基类一般提供一种缺省实现,派生类根据自己的实际需求来判断是否需要覆盖基类的缺省实现。
除此之外,如果担心新的派生类因为遗忘了设计独立的实现,而错误的使用了缺省实现,可以参考pure function可以有着相应的定义,但是在调用时候必须明确指明。这种特性帮助我们设计派生类的时候,如果需要缺省实现就明确要求,否则就自己设计。
用non-virtual函数的意义在于,其不变性凌驾于特异性之上。
class Shape
{
public:
virtual void draw() = 0; // 只提供接口
virtual void error(const std::string& msg); // 提供接口的同时提供一份默认的实现,派生类可以修改为自己的实现版本
int objectID() const; // 提供接口的同时提供一份强制性的实现,派生类一般不应该修改该实现
};
void Shape::draw()
{
cout << "Shape::draw()" << endl;
}
void Shape::error(const std::string& msg) // 接口的默认实现
{
cout << msg << endl;
}
int Shape::objectID() const // 接口的强制实现
{
return 0;
}
class Rectangle : public Shape
{
virtual void draw();
};
void Rectangle::draw()
{
cout << "Rectangle::draw()" << endl;
}
int main()
{
int id;
Shape* ps1 = new Rectangle;
ps1->draw(); // 调用Rectangle::draw
ps1->error("Shape::error"); // 调用Shape::error
id = ps1->objectID(); // 调用Shape::objectID
ps1->Shape::draw(); // 调用Shape::draw()
return 0;
}
这里主要是由设计一个non-virtual函数来设定接口或者执行的框架,但是函数内则调用相应的虚函数来完成具体的实现,这样子,算法的框架整体上相同,但是实现却又不相同。
class GameCharacter{
public:
int healthValue() const
{
…… //做事前工作
int retVal=doHealthValue();//真正做实际工作
…… //做事后工作
return retVal;
}
……
private:
virtual int doHealthValue() const //derived classes可以重新定义
{
……
}
};
将virtual function 替换为“函数指针成员变量”,这是Strategy设计模式的一种分解表现形式
使用function成员变量替换virtual函数,因而允许任何可调用物搭配一个兼容于需求的签名式。
或者将继承体系中的virtual函数替换为另一个继承体系内的virtual函数。传统的Strategy设计模式的实现手法。