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

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.

主站蜘蛛池模板: 安徽省| 黄龙县| 鲁山县| 都兰县| 思茅市| 宁津县| 淳化县| 奇台县| 宁乡县| 大埔区| 上栗县| 孝昌县| 湾仔区| 龙南县| 永寿县| 东至县| 营山县| 寻甸| 德阳市| 峨眉山市| 二手房| 库伦旗| 内江市| 德钦县| 冷水江市| 合水县| 施甸县| 桑日县| 吴川市| 东阳市| 南宫市| 禄丰县| 贵定县| 德安县| 邯郸县| 措美县| 三门峡市| 安龙县| 城口县| 牡丹江市| 怀安县|