《C++编程风格》第四章:虚函数
来源:互联网 发布:孕 防辐射 知乎 编辑:程序博客网 时间:2024/06/03 22:43
原书抄录:
组件之间的交互关系更少并且更简单,将使得程序更容易理解和维护。(低耦合,高内聚)
当我们要决定在一个类中到底是使用数据成员还是函数成员来表示一个特性时,我们首先应该考虑:
这个特性是用属性值来描述的还是由用行为来描述的?- 如果特性是一个属性值,那么用数据成员来表示就更简单。派生类对象将使用这个数据成员,并且可使用它的值。
- 如果这个特性是一种行为(一种操作或者算法),那么我们应该用成员函数来表示它。这个成员函数可以是虚函数,也可以是非虚函数。
我们还要进一步提出问题:
派生类和基类是否有着同样的行为?- 派生类必须表现出不同的行为,那么就应该使用虚函数,这样每个派生类都给出自己的实现。
- 如果所有的派生类都表现出相同的行为,那么他们就可以共享一个在基类中定义的非虚函数。
使用虚函数的开销是难以确定的 。包含虚函数的类中存在虚指针,指向一个描述虚函数的表。
规则总结:
- 派生类在处理继承而来的状态时必须与基类保持一致。(一致性)
- 如果在公有基类中没有定义虚析构函数,那么在所有的派生类或者派生类的数据成员中都应该没有定义虚析构函数。
- 通常情况下,公有基类的析构函数应该被声明为虚函数。
- 将公有的行为迁移到基类中。
- 降低耦合性 —— 将类之间的交互最小化。
- 如果派生类之间的区别在于属性,则用数据成员来表示,如果在于行为,则用虚函数来表示。
- 没有哪个类是完美的;过窄的设计要好于过宽的设计。
- 我们应该考虑使用默认参数的形式来代替函数重载的形式。
章后习题:
很简单,题目就不写了。
答案:是因为group是直接赋值得到的,没有申请内存,自然也不需要删除了。
最后附上本章中研究的代码前后对比。
最初的代码(略有修改):
#include <iostream>#include <cstring>class Vehicle{protected: char *plate;public: Vehicle(){ plate = NULL; } Vehicle(char *p) { plate = new char[strlen(p) + 1]; strcpy(plate, p); } ~Vehicle(){ delete [] plate; } virtual void identify() { std::cout << "generic vehicle" << std::endl; }};class Car: public Vehicle{public: Car(): Vehicle() {} Car(char *p): Vehicle(p) {} void identify() { std::cout << "car with plate " << plate << std::endl; }};class Truck: public Vehicle{public: Truck(): Vehicle() {} Truck(char *p): Vehicle(p) {} void identify() { const char *p = plate ? plate : "<none>"; std::cout << "truck with plate " << p << std::endl; }};class Garage{ int maxVehicles; Vehicle **parked;public: Garage(int max); ~Garage(); int accept(Vehicle *); Vehicle *release(int bay); void listVehicles();};Garage::Garage(int max){ maxVehicles = max; parked = new Vehicle* [maxVehicles]; for(int bay = 0; bay < maxVehicles; ++ bay){ parked[bay] = NULL; }}Garage::~Garage(){ delete [] parked;}int Garage::accept(Vehicle *veh){ for(int bay = 0; bay < maxVehicles; ++ bay){ if(! parked[bay]){ parked[bay] = veh; return bay; } } return -1;}Vehicle* Garage::release(int bay){ if(bay < 0 || bay >= maxVehicles){ return NULL; } Vehicle *veh = parked[bay]; parked[bay] = NULL; return veh;}void Garage::listVehicles(){ for(int bay = 0; bay < maxVehicles; ++ bay){ if(parked[bay]){ std::cout << "Vehicle int bay " << bay << " is :"; parked[bay]->identify(); } }}Car c1("RVR 101");Car c2("SPT 202");Car c3("CHP 303");Car c4("BDY 404");Car c5("BCH 505");Truck t1("TBL 606");Truck t2("IKY 707");Truck t3("FFY 808");Truck t4("PLS 909");Truck t5("SLY 000");int main(){ Garage Park(15); Park.accept(&c1); int t2bay = Park.accept(&t2); Park.accept(&c3); Park.accept(&t1); int c4bay = Park.accept(&c4); Park.accept(&c5); Park.accept(&t5); Park.release(t2bay); Park.accept(&t4); Park.accept(&t3); Park.release(c4bay); Park.accept(&c2); Park.listVehicles(); return 0;}
经过作者(当然是书的作者了)的分析总结修改,最后的代码(运用这些规则后):
#include <iostream>#include <cstring>class Vehicle{protected: char *plate; char *group;public: Vehicle(char *g, char *p); virtual ~Vehicle() = 0; void identify();};Vehicle::Vehicle(char *g, char *p){ group = g; if(p){ plate = new char[strlen(p) + 1]; strcpy(plate, p); } else{ plate = NULL; }}Vehicle::~Vehicle(){ if(plate){ delete [] plate; }}void Vehicle::identify(){ const char *p = plate ? plate : "<none>"; std::cout << group << " with plate " << p << std::endl;}class Car: public Vehicle{public: Car(char *p = NULL): Vehicle("car", p) {}};class Truck: public Vehicle{public: Truck(char *p = NULL): Vehicle("truck", p) {}};class Garage{ int maxVehicles; Vehicle **parked;public: Garage(int max); ~Garage(); int accept(Vehicle *); Vehicle *release(int bay); void listVehicles();};Garage::Garage(int max){ maxVehicles = max; parked = new Vehicle* [maxVehicles]; for(int bay = 0; bay < maxVehicles; ++ bay){ parked[bay] = NULL; }}Garage::~Garage(){ delete [] parked;}int Garage::accept(Vehicle *veh){ for(int bay = 0; bay < maxVehicles; ++ bay){ if(! parked[bay]){ parked[bay] = veh; return bay; } } return -1;}Vehicle* Garage::release(int bay){ if(bay < 0 || bay >= maxVehicles){ return NULL; } Vehicle *veh = parked[bay]; parked[bay] = NULL; return veh;}void Garage::listVehicles(){ for(int bay = 0; bay < maxVehicles; ++ bay){ if(parked[bay]){ std::cout << "Vehicle int bay " << bay << " is :"; parked[bay]->identify(); } }}Car c1("RVR 101");Car c2("SPT 202");Car c3("CHP 303");Car c4("BDY 404");Car c5("BCH 505");Truck t1("TBL 606");Truck t2("IKY 707");Truck t3("FFY 808");Truck t4("PLS 909");Truck t5("SLY 000");int main(){ Garage Park(15); Park.accept(&c1); int t2bay = Park.accept(&t2); Park.accept(&c3); Park.accept(&t1); int c4bay = Park.accept(&c4); Park.accept(&c5); Park.accept(&t5); Park.release(t2bay); Park.accept(&t4); Park.accept(&t3); Park.release(c4bay); Park.accept(&c2); Park.listVehicles(); return 0;}
1 0
- 《C++编程风格》第四章:虚函数
- 第四章 基于对象的编程风格(什么是构造函数和析构函数)
- 第四章-函数式编程
- 第四章 数组和指针 (part3) C 风格字符串
- C语言第四章:函数
- C语言编程风格
- C编程风格
- C语言编程风格
- c语言编程风格
- c/c++编程风格
- C/C++编程风格
- C风格字符串函数
- C++/C编程风格规范
- 《C Primer Plus》第四章编程题
- Linux C编程一站式学习第四章
- c.p.p第四章编程训练
- C和指针第四章编程练习
- 《C程序设计语言》第四章 函数和程序结构
- css知识总结
- Android之Monkey压力测试
- centos下配置mysql 标准配置
- 测试一下
- Spring
- 《C++编程风格》第四章:虚函数
- Zabbix学习笔记(六)---安装和使用中遇到的问题汇总(CentOS)
- HDU 1540:Tunnel Warfare
- 史上最详细的Android Studio系列教程四--Gradle基础
- Android studio jni编译以及第三方so库的引用
- java对数据库进行增删改查的封装(封装以后只要一句话就搞定对数据库的增删改查)
- 用Fragment实现微信Tab切换
- Mybatis中的foreach方法,批量插入和批量删除
- 面试题之java的理解