在设计类的继承时,一般有三种想法:
1 只继承函数接口
2 继承函数接口及其实现,并且允许修改该实现
3 继承函数接口及其实现,但是不允许修改该实现
考虑如下例子:
1 #include <iostream> 2 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 Shape 20 { 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::draw 30 ps1->error("Shape::error"); // 调用Shape::error 31 id = ps1->objectID(); // 调用Shape::objectID 32 33 return 0; 34 }
总结:
- 声明一个纯虚函数的目的是为了让派生类只继承函数接口,不必提供实现
- 声明虚函数的目的是提供接口的同时提供一份默认的实现,派生类可以修改为自己的实现版本
- 声明非虚函数的目的是提供接口的同时提供一份强制性的实现,派生类一般不应该修改该实现(就像上例中的objectID函数,其函数体总是由相同计算方式得到的,因此不必在派生类中修改)