在设计类的继承时,一般有三种想法:
1 只继承函数接口
2 继承函数接口及其实现,并且允许修改该实现
3 继承函数接口及其实现,但是不允许修改该实现
考虑如下例子:
1 #include2 3 class Shape 4 { 5 public: 6 virtual void draw() = 0; // 只提供接口 7 virtual void error(const std::string& msg); // 提供接口的同时提供一份默认的实现,派生类可以修改为自己的实现版本 8 int objectID() const; // 提供接口的同时提供一份强制性的实现,派生类一般不应该修改该实现 9 };10 void Shape::error(const std::string& msg) // 接口的默认实现11 {12 13 }14 int Shape::objectID() const // 接口的强制实现15 {16 return 0;17 }18 19 class Rectangle : public Shape20 {21 virtual void draw();22 };23 void Rectangle::draw(){}24 25 int main()26 {27 int id;28 Shape* ps1 = new Rectangle;29 ps1->draw(); // 调用Rectangle::draw30 ps1->error("Shape::error"); // 调用Shape::error31 id = ps1->objectID(); // 调用Shape::objectID32 33 return 0;34 }
总结:
- 声明一个纯虚函数的目的是为了让派生类只继承函数接口,不必提供实现
- 声明虚函数的目的是提供接口的同时提供一份默认的实现,派生类可以修改为自己的实现版本
- 声明非虚函数的目的是提供接口的同时提供一份强制性的实现,派生类一般不应该修改该实现(就像上例中的objectID函数,其函数体总是由相同计算方式得到的,因此不必在派生类中修改)