代码改变世界

effective c++ 第六章

2011-08-07 20:33  Clingingboy  阅读(294)  评论(0编辑  收藏  举报

 

条款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...