官术网_书友最值得收藏!

Composition versus inheritance

The C++ language provides us with convenient and OOP-friendly syntax so that we can express the inheritance relationship, but the way the compiler processes it resembles composition rather than inheritance. It's actually even better to use composition instead of inheritance wherever it is applicable. The Square class and its relationship with the Rectangle was claimed to be a bad design choice. One of the reasons was the subtype substitution principle, which allowed us to use the Square the wrong way: pass it to a function that modifies it as a Rectangle rather than a Square. This tells us that the is-a relationship is not correct because the Square is not a Rectangle after all. It is an adaptation of a Rectangle rather than a Rectangle itself, which means it doesn't actually represent a Rectangle; it uses it to provide limited functionality to class users.

Users of the Square shouldn't know that it can be used as a Rectangle; otherwise, at some point, they would send invalid or unsupported messages to Square instances. Examples of invalid messages are the calls to the set_width or set_height function. The Square shouldn't actually support two different member functions to modify its sides separately, but it can't hide this because it announced that it's inherited from the Rectangle:

class Square : public Rectangle {
// code omitted for brevity
};

What if we change the modifier from public to private? Well, C++ supports both public and private inheritance types. It also supports protected inheritance as well. When inheriting privately from a class, the subclass intends to use the parent class and has access to its public interface. However, the client code is not aware that it deals with a derived class. Furthermore, the public interface that's inherited from the parent class becomes private for users of the child class. It seems like the Square transforms inheritance into a composition:

class Square : private Rectangle {
public:
void set_side(int side) {
// Rectangle's public interface is accessible to the Square
set_width(side);
set_height(side);
}
int area() {
area_ = Rectangle::area();
return area_;
}
private:
int area_;
};

The client code cannot access members inherited from the Rectangle:

Square sq;
sq.set_width(14); // compile error, the Square has no such public member
make_big_rectangle(sq); // compile error, can't cast Square to Rectangle

The same can be achieved by declaring a Rectangle member in the private section of the Square:

class Square {
public:
void set_side(int side) {
rectangle_.set_width(side);
rectangle_.set_height(side);
}
int area() {
area_ = rectangle_.area();
return area_;
}
private:
Rectangle rectangle_;
int area_;
};

You should carefully analyze usage scenarios and completely answer the is-a question in order to use inheritance without a doubt. Every time you encounter a choice between composition and inheritance, choose composition.

We can omit the modifier when inheriting privately. The default access modifier for classes is private, so class Square : private Rectangle {}; is the same as class Square : Rectangle {};. On the contrary, the default modifier for structs is public.

主站蜘蛛池模板: 毕节市| 岑巩县| 白银市| 邓州市| 新余市| 峨边| 湄潭县| 东台市| 迭部县| 鄢陵县| 滦平县| 利川市| 社会| 临武县| 广宗县| 浦北县| 吉木乃县| 福建省| 驻马店市| 和林格尔县| 买车| 沧源| 乐业县| 永顺县| 日照市| 澄迈县| 开阳县| 重庆市| 景东| 雅安市| 佛山市| 普兰店市| 玉环县| 广饶县| 宿迁市| 渭南市| 祁阳县| 铜梁县| 郑州市| 札达县| 保康县|