Effective C ++ Item 32: Inheritance of the object-oriented (make sure your public inheritance mold the is-a relationship)

A, "is-a" concept

  • Conduct ++ object-oriented programming with C, : The most important rule is that the relationship between public inheritance (public inheritance) means "is-1" (a) of
  • If you make the class D inherits class B with public form, you tell the compiler is:
    • Each type of object D is also an object of type B, respectively. On the other hand is not
    • Objects may be used where B, D may be used as the object. On the other hand is not

Case presentation

  • Student class inherits from the following public Person
class Person {};
class Student :public Person {};
  • Any type of argument obtained Person (pointer-to-Person, or reference-to-Person), and can accept a Student (pointer-to-Student or reference-to-Student) Object
  • E.g:
void eat(const Person& p);
void study(const Student& s);

int main()
{
    Person p;
    Student s;

    eat(p);    //正确
    eat(s);    //正确
    study(s);  //正确
    study(p);  //错误
 
    return 0;
}
  • The above rule only before the establishment of public inheritance. private, protected does not hold

Second, the design right inheritance model

  • Birds can fly, the penguin is a bird. So we might design errors inheritance model below:
    • Although they are birds, penguins, penguins can not fly but
    • Design, we would be wrong of birds fly () virtual function derived class to the Penguin
//鸟类
class Bird {
public:
    virtual void fly();
};

//企鹅,也继承了fly()虚函数
class Penguin :public Bird {};
  • We should modify the code above, the following is the appropriate model:
//鸟类
class Bird {
    //无fly()函数
};

//会飞的鸟类
class FlyingBird :public Bird {
public:
    virtual void fly();
};

//企鹅不会飞
class Penguin :public Bird {

};

Third, in order to "compile" to confirm the relationship between confirm the relationship instead of "run"

  • Then issue the above birds and penguins
  • Penguins can not fly, but we still make Bird defined fly () function, and then let the Penguin inherited Bird, the above difference is that we let Penguin reported an error in the implementation of fly () function (runtime execution) . code show as below:
class Bird {
public:
    virtual void fly();
};

void error(const std::string& msg);
class Penguin :public Bird {
public:
    virtual void fly() {
        error("Attempt to make a penguin fly!");
    }
};
  • The above code is to check such errors at run-time
  • Let's design allows the compiler at compile time checking out the penguins can not fly this error. code show as below:
class Bird {
    //无fly()函数
};


class Penguin :public Bird {
    //...
};

Penguin p;
p.fly();
  • to sum up:
    • Above us the detection of two ways, "Penguins can not fly," such an error. One for the run-in testing, one for the detection of at compile time
    • Of course, we hope that at compile time would determine the relationship Penguins can not fly, so hope a second way (compile-time) instead of the first approach (runtime) to design inheritance

Four, is-a model of some exceptions

Consider a case presentation

  • We let the square class (Square) public class inherited from the rectangle (of the Rectangle) . As follows:

  • Define the rectangle class codes as follows:
class Rectangle {
public:
    virtual void setHeight(int newHeight); //设置高
    virtual void setWidth(int newWidth);   //设置宽

    virtual void height()const; //返回高
    virtual void width()const;  //返回宽
};
  • There are the following function, the following functions are always assert is true, because the function only changes the width, height and has not changed:
//这个函数用来增加r的面积
void makeBigger(Rectangle& r)
{
    int oldHeight = r.height(); //取得旧高度
    
    r.setWidth(r.width() + 10); //设置新宽度
    
    assert(r.height() == oldHeight); //判断高度是否改变
}
  • Square class code defines the following:
class Square :public Rectangle {
    //...
};
  • Now we have the following code:
Square s; //正方形类

//...

assert(s.width() == s.height()); //永远为真,因为正方形的宽和高相同
makeBigger(s); //由于继承,我们可以增加正方形的面积

//...
assert(s.width() == s.height()); //对所有正方形来说,应该还是为真
  • Now consider the above code:
    • The first step, we determine the width and height of the square, according to the principle, assert should return true
    • The second step is called makeBigger () function that changes the width without changing the height
    • The third step is to call assert again should still return true, because here s square
  • Now we can see:
    • While the foregoing we mentioned, acting on the base code for the class, a derived class may also be performed using
    • However, here we can see some of the purposes of the code in the class rectangle (e.g. only changing the width without changing the height), but can be implemented in a rectangular shape (because the width and height of the rectangle should be consistent)
    • Not only is-a relationship exists between the classes. The other two common relationship has-a (a), and is-implemented-terms-of (according to realize something out). These relationships are described in clauses 38 and 39. In shaping these relationships are is-a cause design errors

V. Summary

  • "Public inheritance" mean is-a. Suitable for base classes upon every thing must also apply to the derived classes who, because each derived class objects are also a base class Object

发布了1504 篇原创文章 · 获赞 1063 · 访问量 43万+

Guess you like

Origin blog.csdn.net/qq_41453285/article/details/104757241