Effective C++第三版之(六)Inheritance and Object-Oriented Design

Inheritance and Object-Oriented Design继承与面向对象设计

条款32:Make sure public inheritance models “is-a.”确定public继承的is-a模型
1,令class D以public形式继承class B,每一个D的对象同时也是B的对象,反之不成立,B比D更一般化,D比B更特殊化。
2,适用于base classes上的事情必然适用于derived classes。

条款33:Avoid hiding inherited names.避免隐藏继承名称
1,内层作用域名称会隐藏外层作用域不同类型的相同名称。
2,derived class继承base class并重载了base class的virtual或no-virtual函数,此时derived class内的重载函数隐藏了base class中的所有同名函数,derived class如果是public继承,在条款32中base与derived classes之间的is-a模型,必须继承base class里的重载函数,此时使用using声明使base class里的同名函数在derived class中可见,且base class内的public名称在publicly derived class内也应该是public。

条款34:Differentiate between inheritance of interface and inheritance of implementation.区分接口继承和实现继承
1,public继承由函数接口继承和函数实现继承组成,类似函数声明和函数定义的区别。
1)derived class继承base class纯虚函数的接口,并完成实现。
2)derived class继承base class虚函数的接口和实现,并且可以重写。
3)derived class继承base class非虚函数的接口和实现,可以重载。
2,虚函数强调的派生的特异性,非虚函数代表不变性和强制性,表示派生不需要不同的行为。
3,纯虚函数中可定义缺省行为,派生继承纯虚函数的接口,重写时确定完成自己的实现或调用基类的缺省行为。
1)base class中纯虚函数的声明是接口,定义为实现的缺省行为。
2)derived class继承时需要重写,可以调用base class中的缺省行为,也可以完成自己的实现。

条款35:Consider alternatives to virtual functions.考虑virtual函数以外的选择
1,借由Non-Virtual Interface实现Template Method。
1)以public non-virtual成员函数调用private virtual函数,称为non-virtual interface(NVI),是template method是一种表现形式,non-virtual函数称为virtual函数的wrapper,可在virtual函数之前和之后做一些事前和事后的工作,例锁定/解除互斥器,记录日志等。
2)derived classes须重新定义继承自bass classes的private virtual函数完成自已的实现,且不可调用base class的实现。
3)derived classes重新定义并不调用的private virtual函数,virtual表示功能如何完成,bass classes决定何时调用,两者互不相干。
4)NVI的virtual函数可为protected,如果derived classes virtual函数的实现需要调用bass classes的virtual函数,则令virtual函数为protected,如果virtual函数为public,则不是NVI手法。
2,借由Function Pointers实现Strategy模式。
1)non-member函数无法访问class non-public成员,可声明non-member函数为friend,或是提供public访问函数,但会弱化class封装。
2)以函数指针成员变量替代virtual函数,可弥补封装性的降低,base class定义函数指针,构造函数初始化函数指针,可在member函数内修改函数指针指向的non-member函数,另一member函数调用指针指向的non-member函数,non-member函数形参为class对象执行不同的操作。
3,借由std::function完成Strategy模式。
1)模板function可指向相同调用形式的所有可调用对象,函数,函数指针,lambda表达式,bind创建的对象以及重载了函数调用运算符的类。
2)相同的返回类型和形参即具有相同的调用形式。
4,古典的Strategy模式。
1)古典Strategy模式在继承体系中定义另一继承体系的base classes指针,成员函数调用该指针指向的base class或derived class对象的virtual函数,将继承体系中的virtual函数替换为另一继承体系的virtual函数。

条款36:Never redefine an inherited non-virtual function.绝不重新定义继承的non-virtual函数
1,virtual函数是动态绑定,non-virtual函数是静态绑定,base class的指针或引用指向derived class对象,non-virtual函数也是调用的base class。
2,derived class public继承base class,条款32中public继承代表is-a关系,derived 3,class重新定义non-virtual函数则与is-a关系矛盾。
条款34非虚函数代表不变性和强制性,如若重新定义non-virtual则与不变性矛盾。

条款37:Never redefine a function’s inherited default parameter value.绝不重新定义继承而来的缺省参数值
1,条款36中不可重新定义继承而来的non-virtual函数,virtual函数是动态绑定,而缺省参数值却是静态绑定的。如果缺省参数值是动态绑定的,编绎器在运行期为virtual函数决定适当的参数值,运行复杂且效率大大降低。
1)derived class的virtual函数与base class不同的缺省参数值,静态绑定调用时使用derived class的缺省参数值,动态绑定使用的base class的缺省参数值。
2)derived class没有缺省参数值时,动态绑定依然使用base class缺省参数值,静态绑定必须提供参数值。
2,derived class的virtual函数与base class相同的缺省参数值则会代码重复,且base class缺省参数值改变时,所有derived class的参数值也需要改变。使用条款35中virtual函数的替代设计如NVI,令base class内的public non-virtual函数调用private virtual函数,non-virtual函数中指定缺省参数,derived class重新定义private virtual函数,实现多态。

条款38:Model “has-a” or “is-implemented-in-terms-of” through composition.通过复合关系建模“has-a”或“按某物实现”
1,复合关系即类型中含其他类型的对象。
1)程序中的对象相当于塑造的世界中的某些事物,这样的对象属于应用域。
2)其他对象则是实现上的细节,例buffer缓冲区、mutexes互斥器、search trees查找树等,这些对象相当于软件的实现域。
3)当复合发生于应用域的对象之间,则是has-a关系,当发生于实现域内则是is-implemented-in-terms-of(根据某物实现出)关系。
2,public继承表示is-a,复合与public继承完全不同,在应用域复合意味has-a,在实现域复合意味is-implemented-in-terms-of。

条款39:Use private inheritance judiciously.明智地使用私有继承
1,如果继承关系是private,编绎器不会自动将derived class对象转换为base class对象,而public继承可以。
1)private base class继承而来的所有public和protected成员,在derived class中为private属性,derived class内部可使用这些成员和成员函数。
2)根据条款34,private继承表示实现被继承,接口应忽略。
3)derived class获得了base class的属性,但继承而来的private virtual会作为接口被继承下去。
2,private继承表示is-implemented-in-terms-of,条款38复合的意义也是如此,所以尽可能使用复合,还可降低编绎的依赖性,必要时才使用private继承。
1)private继承表示is-implemented-in-terms-of而不是is-a关系,当derived class需要访问base class的protected成员,或需要重新定义virtual函数,或需要空间最优化时,可选择private继承。
2)当class没有non-static成员变量,没有virtual函数,也没有virtual base classes,没有任何数据,sizeof该类型对象为非零,通常编绎器会插入一个char到空对象内。在复合中,该类型对象获得一个char大小,并且由于内存对齐最终复合类型不止增加一个char大小内存,而当该class作为private继承的base class时,derived class并不会多余增加内存。这就是EBO(empty base optimization:空白基类最优化),通常在单一继承下可行,不增加derived classes的大小。
3)empty classes可以有typedefs, enums, static成员变量和non-virtual函数。

条款40:Use multiple inheritance judiciously.明智地使用多重继承
1,多重继承(MI)下可能从不同的base classes继承相同的名称而导致歧义,即使冲突名称分别为public与private,编绎器先名字查找再类型检查调用是否合法,则须在调用时指定base class避免冲突。
2,多重继承下不同的base classes有相同的更高级的base classes,导致钻石型多重继承,derived class与某个base class有一条以上相通路线,则base class中某个成员在derived class中存在多个。
1)为避免继承的成员变量重复,令base class为virtual base class,并virtual public继承此base class。
2)virtual继承比non-virtual继承的体积大,访问virtual base classes成员变量比访问non-virtual base classes的成员速度慢,且virtual base classes初始化较复杂,由最底层derived class负责初始化,所以非必要不使用virtual base,尽量使用non-virtual继承。
3)必须使用virtual base classes时,尽量避免放置数据,避免初始化和赋值的复杂情况。
3,多重继承在public继承某个class接口,private继承另一个协助实现的class时使用更佳。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值