Effective C++第六章-继承与面向对象设计
来源:互联网 发布:超级英雄官方数据 编辑:程序博客网 时间:2024/05/18 06:48
几种继承方法
类型之间的public继承–is a(derived class is a base class.)
类型之间的复合关系–has a或根据某物实现出
class address{...};class phonenumber{...};class person{public:...private:std::string name;address theaddress;phonenumber thephone;};
private继承:意味着根据某物实现出(如果D以private形式继承B,意思是D对象根据B对象实现而得)
private继承意味只有实现部分被继承,接口部分应略去。
通常比复合的级别低。但是当你面对“并不存在is-a关系”的两个class,其中一个需要访问另一个的protected成员,或需要重新定义其一或多个virtual函数,设计为private继承是合理的。
多重继承(multiple inheritance,MI)-继承一个以上的基类
//多重继承可能带来的歧义问题class first{public:void checkout();};class sec{private:virtual void checkout();};class thir:public first,public sec{...};thir mp;mp.checkout();//wrong,first和sec都有checkout函数,且只有first的public成员函数checkout是可取用的。但是C++是先找出最佳匹配函数后才检验可取性,first和sec的checkout具有相同的匹配程度,因此造成歧义mp.first::checkout();//rightmp.sec::checkout();//wrong,提示“尝试调用private成员函数”的错误。
避免继承中的名称遮掩
int x;void func(){ double x; std::cin>>x;}//局部的double x遮掩全局的int x
在类的继承中,derived class作用域被嵌套在base class作用域。
class base{public: int x;private: virtual void mf1() = 0;//纯虚函数 virtual void mf2(); void mf3();};class derived:public base{public: virtual void mf1(); void mf4();};
class base{public: int x;private: virtual void mf1() = 0;//纯虚函数 virtual void mf1(int); virtual void mf2(); void mf3(); void mf3(double);};class derived:public base{public: virtual void mf1(); void mf3(); void mf4();};
基于作用域的名称遮掩规则会使得base class内所有名为mf1和mf3的函数都被derived class内的mf1和mf3函数遮掩掉了。
derived d;int x;double y;d.mf1();//rightd.mf1(x);//wrongd.mf2();//rightd.mf3();//rightd.mf3(y);//wrong//不论是virtual还是普通函数,只要子类中有同名函数,不管形参是什么,编译器都不会再往父类作用域里面找了。
消除遮掩的方法:
利用using声明式
如果你继承base class并加上重载,而你又希望重新定义或覆写其中一部分,那么你必须为那些原本会被遮掩的每个名称引入一个using声明式,否则某些你希望继承的名称会被遮掩。
class base{public:int x;private:virtual void mf1() = 0;//纯虚函数virtual void mf1(int);virtual void mf2();void mf3();void mf3(double);};class derived:public base{public:using base::mf1;using base::mf3;//使得base class内名为mf1和mf3的所有在derived类作用域内都可见virtual void mf1();void mf3();void mf4();};
derived d;int x;double y;d.mf1();//right,调用derived::mf1()d.mf1(x);//right,调用base::mf1(int)d.mf2();//right//调用base::mf2()d.mf3();//right//调用derived::mf3()d.mf3(y);//right,调用base::mf3(double)
但using声明式会令继承而来的某给定名称之所有同名函数在derived class中都可见~适合于public继承(派生类继承基类的所有)
using声明和using指示
利用转交函数(forwarding function)
在private继承时可以实现:派生类只继承基类的部分,比如derived唯一想继承mf1的无参数版本。此时不能使用using声明式,使用转交函数:
class base{...};//同前class derived:private base{public:virtual void mf1()//转交函数{ base::mf1();}//暗自成为inline};
derived d;int x;d.mf1();//rightd.mf1(x);//wrong
区分函数的接口继承和函数的实现继承
- 声明一个纯虚函数的目的是为了让derived class只继承函数接口
- 声明非纯虚函数(impure virtual)的目的是让derived class继承该函数的接口和缺省实现
- 声明一个non-virtual函数的目的是为了令derived class继承函数的接口及一份强制性实现
成员函数的接口总是会被继承,下面分别通过代码详细说明。
声明一个纯虚函数的目的是为了让derived class只继承函数接口。但是注意:
纯虚函数必须在派生类中重新声明
也可以为纯虚函数提供定义,例1
--example1class airplane{public:virtual void fly()=0;};void airplane::fly(){//pure virtual函数的实现...}
声明非纯虚函数(impure virtual)的目的是让derived class继承该函数的接口和缺省实现。如果derived class对该函数不想做出特殊行为,则可以用base class提供的缺省实现。
class airplane{public:virtual void fly();};void airplane::fly(){//缺省实现}class modelA:public airplane{};//如果modelA不想使用缺省实现但是忘记自己对fly函数进行重新定义了呢?
切断接口和缺省实现之间的连接:
class airplane{public:virtual void fly()=0;protected://protected成员可以被派生类对象访问,不能被用户代码(类外)访问。void defaultfly();//该函数应该是non-virtual函数,因为任何derived class都不该重新定义该函数。};void airplane::defaultfly(){...}
此时airplane类的接口为fly,缺省实现为defaultfly,若派生类想使用缺省实现可在fly函数中对defaultfly函数做一个inline调用。
class modelA:public airplane{public:virtual void fly(){ defaultfly();}};class modelB:public airplane{public:virtual void fly();};void modelB::fly(){ ...}
声明一个non-virtual函数的目的是为了令derived class继承函数的接口及一份强制性实现
派生类绝不能重新定义non-virtual函数。
pure virtual函数、impure virtual函数、non-virtual函数之间的差异使你能精确指定想让derived class继承的东西:只继承接口、或是继承接口和一份缺省实现、或是继承接口和一份强制实现。
virtual函数的替换方案(涉及到了Template Method设计模式和Strategy设计模式)
有很多种替换方案~只提一下non-virtual interface(NVI),Template Method设计模式的一种特殊形式。以public non-virtual成员函数(该函数用来控制virtual函数被调用的方法和时间)包裹较低访问性(private或protected)的virtual函数(该函数用来具体实现)。
class base{private: int Base_x;public: int process() const { int Result = step1(); ... }private: virtual int step1() const { return Base_x; }};class derived : public base{private: virtual int step1() const//派生类可以重新定义 { return Base_x*2; }};
绝不重新定义继承而来的缺省参数值
因为virtual函数是动态绑定的,但是缺省参数值是静态绑定的。
也就是说,有可能调用一个定义于derived class内的virtual函数的同时,却使用base class为它指定的缺省参数值。例:
class shape{public: enum shapecolor{red, green, blue}; virtual void draw(shapecolor color = red) const = 0;//pure virtual,缺省参数值color};class rectangle:public shape{public: virtual void draw(shapecolor color = green) const;//此处改变了缺省参数值};...//调用:shape* pc = new rectangle;//动态类型是rectangle,静态类型是shapepc.draw();//调用rectangle的draw,调用shape的color参数值
因此,需要注意:1、派生类改变(重新定义)缺省参数值。2、基类的缺省参数值的改变,则需要改变派生类。
可以采用其他设计替代virtual函数,例如NVI(non-virtual interface)
class shape {public: enum shapecolor{red, green ,blue}; void draw(shapecolor color = red) const//draw函数是non-virtual函数,不能被覆写,因此color的缺省值不会被改变 { dodraw(color); }private: virtual void dodraw(shapecolor color)const = 0 ;};class rectangle :public shape{public: ..private: virtual void dodraw(shapecolor color)const;};
- 《Effective C++》第六章:继承与面向对象设计
- Effective C++ 第六章--继承与面向对象设计笔记
- Effective C++第六章-继承与面向对象设计
- [Effective C++] 继承与面向对象设计
- 《Effective C++》继承与面向对象设计
- Effective C++读书笔记 第六部分 继承与面向对象设计
- 第六章 继承与面向对象设计
- 第六章 继承与面向对象设计
- Effective C++学习有感--第六章 继承与面向对象设计(一)
- Effective C++学习有感--第六章 继承与面向对象设计(二)
- (Effective C++)第六章 继承与面向对象(Inheritance and Object-Oriented Design)
- Effective C++(六)继承与面向对象设计
- Effective C++(六)继承与面向对象设计
- effective C++: 6.继承与面向对象设计
- Effective c++(笔记)之继承关系与面向对象设计
- Effective C++(六)继承与面向对象设计
- <<Effective C++>> 读书笔记6: 继承与面向对象设计
- Effective C++ -- 继承与面向对象设计
- verilog时钟频率对应关系
- Fragment 基类的常规抽取
- java.sql.SQLException: statement is closed语句被关闭 druid连接池报错
- 24L01配置函数详解
- 为什么你的手机能上网打电话?
- Effective C++第六章-继承与面向对象设计
- js控制30秒自动页面跳转,带读秒
- 高精度运算
- equals()和hashCode()区别
- spring(基础3)
- pulltorefresh_library刷新样式
- 简单易懂的例子解释隐马尔可夫模型
- db
- 【原创】【组合数学】Uva1635 无关的元素