条款32:确定你的public继承塑模出is-a关系
确认子类和父类的关系是正确的
class Person {...};
class Student: public Person {...};
以下有问题
class Bird {
public:
virtual void fly(); // birds can fly
...
};
class Penguin:public Bird { // penguins are birds
...
};
属于设计问题,以上可以把fly声明为虚方法,然后在Penguin报error都可以
条款33:避免遮掩继承而来的名称
下列代码出现遮掩问题
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();
...
};
使用示例
Derived d;
int x;
...
d.mf1(); // fine, calls Derived::mf1
d.mf1(x); // error! Derived::mf1 hides Base::mf1
d.mf2(); // fine, calls Base::mf2
d.mf3(); // fine, calls Derived::mf3
d.mf3(x); // error! Derived::mf3 hides Base::mf3
要想在子类使用父类被遮掩的方法可以用using关键字,以下使得上面的代码正常运行
class Derived: public Base {
public:
using Base::mf1; // make all things in Base named mf1 and mf3
using Base::mf3; // visible (and public) in Derived's scope
virtual void mf1();
void mf3();
void mf4();
...
};
使用private隐藏基类函数,只允许在子类调用
class Derived: private Base {
public:
virtual void mf1() // forwarding function; implicitly
{ Base::mf1(); } // inline (see Item30)
...
};
...
Derived d;
int x;
d.mf1(); // fine, calls Derived::mf1
d.mf1(x); // error! Base::mf1() is hidden
条款34:区分接口继承和实现继承
class Shape {
public:
virtual void draw() const = 0;
virtual void error(const std::string& msg);
int objectID() const;
...
};
抽象方法必须实现即接口继承,具备抽象方法的类(抽象类)无法直接实例化 (虚方法)实现方法子类可以选择不实现
条款35:考虑virtual函数以外的其他选择
1.模板模式,重写部分函数
class GameCharacter {
public:
int healthValue() const // derived classes do not redefine
{ // this — see Item 36
... // do "before" stuff — see below
int retVal = doHealthValue(); // do the real work
... // do "after" stuff — see below
return retVal;
}
...
private:
virtual int doHealthValue() const // derived classes may redefine this
{
... // default algorithm for calculating
} // character's health
};
2.策略模式
class GameLevel {
public:
float health(const GameCharacter&) const; // health calculation
... // mem function; note
}; // non-int return type
class EvilBadGuy: public GameCharacter { // as before
...
};
class EyeCandyCharacter: public GameCharacter { // another character
... // type; assume same
}; // constructor as
条款36:绝不重新定义继承而来的non-virtual函数
同条款33,必须去这么做
class B {
public:
void mf();
...
};
class D: public B {
public:
void mf();
...
};
条款37:绝不重新定义继承而来的缺省参数值
以下子类重写的缺省参数值将会无效(静态绑定,为了运行效率)
// a class for geometric shapes
class Shape {
public:
enum ShapeColor { Red, Green, Blue };
// all shapes must offer a function to draw themselves
virtual void draw(ShapeColor color = Red) const = 0;
...
};
class Rectangle: public Shape {
public:
// notice the different default parameter value — bad!
virtual void draw(ShapeColor color = Green) const;
...
};
条款38:通过复合塑模出has-a或”根据某物实现出”
不通过继承的方式,而是通过复合和适配的方式,实现功能,避免继承父类的耦合度,优先采用此方案
class Address { ... }; // where someone lives
class PhoneNumber { ... };
class Person {
public:
...
private:
std::string name; // composed object
Address address; // ditto
PhoneNumber voiceNumber; // ditto
PhoneNumber faxNumber; // ditto
};
用list实现Set
template<class T> // the right way to use list for Set
class Set {
public:
bool member(const T& item) const;
void insert(const T& item);
void remove(const T& item);
std::size_t size() const;
private:
std::list<T> rep; // representation for Set data
};
条款39:明智而审慎地使用private继承
private继承意味着implemented-in-terms-of(根据某物实现出)。用意是为了采用基类已经备妥的某些特性
条款40:明智而审慎地使用多重继承
1.函数重名调用
class BorrowableItem { // something a library lets you borrow
public:
void checkOut(); // check the item out from the library
...
};
class ElectronicGadget {
private:
bool checkOut() const; // perform self-test, return whether
... // test succeeds
};
class MP3Player: // note MI here
public BorrowableItem, // (some libraries loan MP3 players)
public ElectronicGadget
{ ... }; // class definition is unimportant
MP3Player mp;
mp.checkOut(); //wrong ambiguous! which checkOut?
mp.BorrowableItem::checkOut(); // ah, that checkOut...