- 确定你的public继承塑模出is-a关系
- public继承和is-a的之间的等价关系很简单。例如动物和鸟,鸟一定是动物,而动物不一定是鸟。
- public继承意味着is-a。适用于base classes身上的每一件事情也是一定适用于派生类身上的,因为每一个派生类对象也都是一个base classes对象。
- 避免遮掩继承而来的名称
-
int x;//global变量 void somefunc(){ double x;//local变量,这个变量会遮掩吊全局变量,在这个函数体内,改变的是double的x。 cin>>x; }
- 实际上类的继承中也是会发生这样的事情。派生类继承基类,派生类的作用域是嵌套在基类中的。
class base{ private: int x; public: 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(); }; int main(){ derived d; int x; d.mf1();//true 调用derived::mf1 d.mf1(x);//wrong derived::mf1遮掩了base::mf1(int) d.mf2();//true d.mf3();//true d.mf3(x);//wrong derived::mf3遮掩了base::mf3(double) } //这里面的是名称遮掩规则,不考虑参数的类型,而是直接考虑名称,这里直接相关的东西是作用域这个东西。 //解决办法:在main函数中,明确的使用using声明表达式去显示的调用自己享用的函数即可。
- 在public继承下,derived类的名称会遮掩base class内的名称。在public继承下面从来没有人希望如此
- 我们可以使用using声明表达式去显示的调用想调用的函数或者变量等。
-
- 区分接口继承和实现继承
- 一个基类有三个函数:一个pure virtual,一个 impure virtual,一个non virtual。
- 声明一个pure virtual函数的目的是让片派生类只是继承函数接口
- 声明一个impure virtual函数的目的是让派生类继承该函数的接口给和缺省实现:继承该非纯虚函数,既可以自己实现这个函数,也可以缺省的调用父类的这个函数而不去重写派生类中的这个函数
- 声明一个non virtual函数的目的是为了令派生类继承函数的接口给及一份强制性实现。
- 接口继承和实现继承不同,在public继承下,派生类总是继承base class的接口
- pure virtual函数只是具体制定接口继承,impure virtual函数具体指定接口继承和缺省的实现继承,non virtual函数具体制定接口继承以及强制性实现继承
- 一个基类有三个函数:一个pure virtual,一个 impure virtual,一个non virtual。
- 绝对不重新定义继承而来的non-virtual
- non-virtual是静态绑定的,virtual是动态绑定的。
class b{ public: void mf(); }; class d:public b{ void mf(); }; int main(){ d x; b* pb=&x; pb->mf(); d* pd=&x; pd->mf(); } //其中b的mf函数和d的函数mf都是静态绑定的,non-virtual函数。但是如果mf是一个virtual函数的话,那么virtual是动态绑定的,mf是个virtual函数,不论通过pb还是pd //调用mf,都会是调用的pd::mf()。
- non-virtual是静态绑定的,virtual是动态绑定的。
- 绝不重新定义继承而来的缺省参数值
- virtual是动态绑定的(调用一个virtual函数时,究竟调用哪一个实现代码,由调用的那个独享的动态类型),non-virtual是静态绑定的,缺省参数值也是静态绑定的。
class shape{ public: enum shapecolor{red,green,blue}; virtual void draw(shapecolor color = red)const=0;//带有默认参数的virtual函数绝对不重新定义该默认参数 ... }; class rectangle:public shape{ public: virtual void draw(shapecolor color = red)const;//这样就代码重复了 }; //修改的版本 class shape{ public: enum shapecolor{red,green,blue}; void draw(shapecolor color = red)const{ dodraw(color); } ... private: virtual void dodraw(shapecolor color)cosnt = 0; }; class rectangle:public shape{ public: ... ; private: virtual void dodraw(shapecolor color)const;//这里不需要指定默认参数值 }; //这里就是利用了non-virtual函数永远不会被派生类重写,这样就能保证默认参数值不会被修改和重新定义了。
- virtual是动态绑定的(调用一个virtual函数时,究竟调用哪一个实现代码,由调用的那个独享的动态类型),non-virtual是静态绑定的,缺省参数值也是静态绑定的。
- 通过复合塑模出has-a或者根据某物实现出
- 复合:类型之间的一种关系,当某种类型的对象内含它种类型的对象。它意味着has-a或者是is-implement-in-terms-of(根据某物实现出)。当复合发生在应用域内的对象的时候表现出has-a关系,发生在实现域表现is-implement-in-terms-of。
- 应用域:人,汽车,动物,这些属于应用域。
- 实现域:像缓冲器,查找树,互斥器这种东西属于实现域。
- 复用和继承完全不同的,复用不用去继承。
- 复合:类型之间的一种关系,当某种类型的对象内含它种类型的对象。它意味着has-a或者是is-implement-in-terms-of(根据某物实现出)。当复合发生在应用域内的对象的时候表现出has-a关系,发生在实现域表现is-implement-in-terms-of。
- 明智而审慎的使用private继承
- private意味着;private的派生对象系统是不会自动的将它变成一个base类对象的。从private base class中继承而来的所有成员在derived class都会变成paivate属性。
- private意味着:根据某物实现出is-implement-in-terms-of。如果D以private形式继承B,意思是D对象根据B对象实现而得。
- 由于复合和private继承貌似有重合的部分,但是我们尽可能的使用复合,在必要时才使用private继承。
- 明智而审慎的使用多重继承
- 当多重继承出现的时候,程序有可能从一个以上的base class继承相同名称的函数或者其他东西。会产生较多的起义。
- 多重继承比单一继承复杂,他可能导致新的起义性,以及对virtual继承的需要。
- virtual继承会增加大小,速度,初始化复杂度等等成本。如果virtual base class不带任何数据,将是最具实用价值的情况。
- 多重继承的确有正当用途。其中一个情节设计public继承某个interface class和private继承某个协助实现的class 的两辆组合。
时间: 2024-09-30 20:50:49