Author: Breaker <breaker. zy_at_gmail>
For the design methodology of the C ++ class hierarchy, note-to-self + keynote + cross-reference notes
This article is refined in the bbwindow example of [CPP Lang] 12.4, 15.2, involving only design
For details about syntax, refer to [CPP Lang] ch12, 15; [CPP primer] ch17, 18.
For details about play with bits, refer to [CPP objmodel] 5.2.
Keyword: class hierarchy, multiple inheritance, abstract class, virtual base class, abstract factory, clone
Directory
- Example scenario
- Separation implementation and Interface
- Replacement implementation
- Repeat base class
- Sharing implementation
- Abstract Factory
- Clone Mode
Sample Scenario ^
Ivalbox: an abstract class that retrieves the GUI element of an integer. It is not bound to a specific GUI element, such as the slider or dial.
Ivalslider: a slider-based ivalbox implementation, similar to the ivaldial dial implementation, which represents a specific GUI element in the ivalbox class hierarchy. These classes can be further extended, such as deriving popupivalslider from ivalslider
Bbwindow: third-party GUI element implementation, such as cwnd of MFC. The class hierarchy of ivalbox relies on the class hierarchy of bbwindow to implement GUI features (such as drawing ). Bbwindow is just a form name, which can be replaced. Its meaning is the same as replacing MFC with QT, which enables the class hierarchy of ivalbox to reduce dependencies on specific GUI elements.
UML: Old hierarchy
Design essentials:
-
Using bbwindow is not a basic part of the ivalbox concept. Over-reliance on bbwindow makes it difficult to replace bbwindow
-
Variable data is the implementation part. When it invades an interface (abstract class), it will affect the flexibility of the interface.
Two-type interfaces: public interface vs. Protected Interface
Interface: A translation interface or a translation interface. Sometimes it represents a function, and sometimes it represents the aggregation of a function (class, namespace). It is determined by context. According to [effect CPP] item 18: each interface is yours and the customerCodeInteractive means
Public interface: used by users
Protected interface: used by the derived class
Strict guide: data members are better kept private so that writers of derived classes cannot mess with them.
Inference: a protected interface shoshould contain only functions, types, and constants.
For more information about private data member, see [effect CPP] item 22
Over strict?
Is old hierarchy bad design?
In fact, most of the time when I use MFC, This is the method most people use the GUI framework.
The question is not absolute bad design or good design, but what is the goal? Application Development vs. Library Development, cross-platform vs. Dedicated-Platform
The improved design below is more flexible and glamorous than old hierarchy, but it also brings additional burden (such as understanding and maintenance), pros and cons choose their own
Separation implementation and interface ^
UML: separate implementation and Interface
Interface line: Hierarchy formed by interface inheritance
Implementation line/extended line: Hierarchy formed by inheritance
Design essentials:
Public inheritance vs. Protected/private inheritance
Another expression is: interface inheritance vs. Implementation inheritance. For details, see [effect CPP] item 40. Note that item 34 has nothing to do with this design. Although the title is the same, it is for member function. Here it is for class.
Public inherits the relationship between "is-a" (see [effect CPP] item 32 ), the relationship between protected and private "implemented-in-terms-of" (see [effect CPP] item 39)
Difference between protected and private: the implementation of private ends with the direct derived class, while the implementation of protected can be further extended.
Alternative Technology: Public inheritance + composition combination
When used to implement the domain, the relationship between the composite model "implemented-in-terms-of" is the same as that of protected/private. For details, see [effect CPP] item 38.
Use protected/private inheritance or composite judgment. For details, see [effect CPP] item 39. inheritance will result in EBO (empty base optimization) blank base class optimization.
Replacement implementation ^
This is a benefit of separating implementations from interfaces.
UML: Substitute implementation
The bbslider in the figure indicates that bbivalslider can be implemented with a more specific GUI element, rather than a more general bbwindow. It is like changing from cwnd of MFC to csliderctrl
You can use the same method for expansion to get the big one:
UML: Substitute implementation, complicated
There is no need to worry about the specific meaning. The Design Inference here is more interesting: A system should show the user an abstract class hierarchy, and its implementation uses a traditional hierarchy.
Is it a little dogma? Where does the traditional hierarchy come from? Should we build a framework that spans multiple GUI frameworks?
Duplicate base class ^
Use the virtual base class to remove the replicated base class duplicate base class. For details, see [effect CPP] item 40.
The purpose of this method is:
- Glue two irrelevant classes. This is the Virtual Multi-inheritance that we should forget. Even Bjarne also says it is crude, valid tive, and important, but not very interesting.
- For the following shared implementations, this is logically meaningful
Sharing implementation ^
UML: Share implementation
Here, diamond-shaped inheritance diamond inheritance has the significance of making popupivalslider classes (I .e. bbpopupivalslider) share implementations in ivalslider classes (I .e. bbivalslider) to reduce Coding
So another interesting inference is that all the derivation of the abstract class that makes up the application interface should be virtual. [effect CPP] item 40 also says that public inheritance should always be virtual.
However, this is not the case. The simplest counterargument is the efficiency factor. For details, see [CPP Lang] 15.2.5 and [effect CPP] item 40.
You can use the non-data member class to repeat the base class.
So I came back again
Abstract Factory ^
The constructor cannot be virtual. The truth is simple: it does not know the exact type of the object and how to construct it (the essence of the constructor is the initialization of bits in the object layout)
Abstract Factory and clone mode are called virtual constructor, because they use virtual functions to perform a roundabout task of constructor: Create Objects Based on some clues.
- For a real constructor, the clue is the constructor parameter.
- For abstract factories, the clue is:ProgramPre-configured during initialization. Its form (typical) can be the uuid ID of the class (e.g. com's iclassfactory)
- For clone mode, the clue is the exact type of the current object
It is impossible to create an absolute abstraction (without clues), that is, there is no syntax support (Virtual constructor), and there is no logic significance: When you want a pencil, you can say that I want a pencil, it can also be said that I want something in the pencil case (Abstract With clues), but not just that I want something (Abstract without clues)
Why abstract class?
UML: Abstract Factory
Reduces the dependency on specific implementation classes (constructors) when an object is created. For example, when creating ivaldial, you must use the bbivaldial or lsivaldial constructor.
When the abstract class hierarchy is complex and has an expectation of changing from one implementation system to another (for example, changing from bbwindow to lswindow, A one-time loading method is required to implement various object creation methods in the system, so the abstract factory will play a role:
- Create a factory object
- Load a specific factory class object into an abstract factory class Object (reference, pointer)
- Create an abstract block class with an abstract factory class Object
- Uses the abstract method to construct the block class. It is dynamically bound to the method for constructing the block class.
1 and 2 are the execution settings in the program initialization stage, and 3 and 4 are the activities in the routine stage of the program.
Therefore, the abstract factory is associated with the abstract class hierarchy.
Clone Mode ^
UML: Clone Pattern
Why clone?
There is an object on hand, only know its abstract type (the exact type has been lost), to copy a large number of copies of this object, and the copy must be consistent with its exact type
A clonable abstract base class can be defined to define clone functions, but not required.
The clone mode can benefit from covariance variation of the return value type of the function override. VC 2005 + supports covariant
Reference books ^
- [CPP Lang] "The C ++ programming language, special ed", Bjarne stroustrup
- [Effect CPP] "valid tive C ++, 3ed", Scott Meyers
- [CPP primer] "C ++ primer, 3ed", Stanley Lippman, Joseph Lajoie
- [CPP objmodel] "inside the C ++ object model", Stanley Lippman