3.4 "Inherit" with data Member
In the C + + inheritance model, what a derived class object shows is the sum of its own members plus its base class members. As for derived class members and base class The order of members is not specified in C + + standard: Theoretically the compiler is free to arrange. On most compilers, the base class members always appear first, except for the virtual base class.
After understanding this inheritance model, then if you provide two abstract models for 2D or 3D coordinate points, the following:
Support Abstract data types
Class Point2d {
Public
Constructor
Operations
Access functions
Private
float x, y;
};
Class Point3D {
Public
Constructor
Operations
Access functions
Private
float x, y, Z;
};
This and "provide a two-or three-layer inheritance structure, each layer (representing a dimension) is a class, derived from the lower-dimensional hierarchy" What is the difference?
The following subsections will cover four scenarios such as "single inheritance with no virtual functions", "single inheritance with virtual functions", "Multiple Inheritance", "Virtual inheritance".
As long as inheritance is not polymorphic
Imagine that programmers may want to be able to share the same entity regardless of the 2D or 3D coordinate points, but can continue to use entities that are related to type nature (so-called type-specific). There is a design strategy, is to derive a Point3D from point2d, so Point3D will inherit everything from the x and Y coordinates (including the data entity and the action method), and the effect is to share the "data itself" and "Data processing method" and localize it. In general, specific inheritance ( Concrete inheritance) does not increase the extra burden on space or access time.
Class Point2d {
Public:
point2d (float x = 0.0, float y = 0.0): _x (x), _y (y) {}
float X () { return _x; }
float y () {return _y;}
void x (float newx) {_x = newx;}
void y (float newy) {_y = Newy;}
void operator+= (const point2d &RHS) {
_x + = Rhs.x ();
_y + = Rhs.y ();
}
Protected:
float _x, _y;
};
//Inheritance from concrete class
class Point3d:public point2d {
Public:
point3d (float x = 0.0, Floa T y = 0.0, float z = 0.0)
: point2d (x, y), _z (z) {}
float Z () {return z;}
void Z (float newz) {_z = Newz;}
void operator+= (const Point3D &RHS) {
point2d::operator+= (RHS);
_z + = Rhs.z ();
}
Protected
float _z;
};
The advantage of this design is that you can localize the program code that manages x and Y coordinates, and this design clearly shows a close relationship between the two abstract classes. When these two class are independent, Point2d object and Point3D The Declaration and use of object does not change. Therefore, the users of these two abstract classes do not need to know whether objects is a separate class type or have an inherited relationship with each other.
What are the easy mistakes of making a pair of "Type/subtype" with the original two independent classes and having an inheritance relationship? Inexperienced people may repeat the design of functions with the same operations. In the example of constructor and operator+=, They are not made into the inline function. Point3D an object's initialization or addition operation, it will require part of the Point2d object and part of the Point3D object as cost. The second easy mistake is to break a class into two or more layers, possibly for " The abstraction of the class system, and the space required for expansion. The C + + language guarantees that the base class Subobject appearing in the derived class has its integrity. It is the focus, as follows:
Class Concrete {
Public
// ...
Private
int Val;
Char C1;
Char C2;
Char C3;
};
In a 32-bit machine, the size of each concrete class object is 8 bytes, broken down as follows:
1. Val occupies 4 bytes
2. Clc,c2 and C3 each occupy 1 bytes
3. Alignment (adjustment to void boundary) requires 1 bytes
Now suppose that, after some analysis, a more logical expression is decided, splitting the concrete into three-layer structures:
Class Concrete1 {
Public
// ...
Private
int Val;
Char bit1;
};
Class Concrete2:public Concrete1 {
Public
// ...
Private
Char bit2;
};
Class Concrete3:public Concrete2 {
Public
// ...
Private
Char bit3;
};
From the point of view of design, this structure may be reasonable, but from the point of view of efficiency, it may be trapped in the fact that the size of Concrete3 object now is bytes, one more than the original design.
What's going on, mentioned before "base class Subobject in derived class":
The Concrete1 contains two members:val and bit1, adding up to 5 bytes. And a Concrete1 object actually uses 8 bytes, including 3 bytes for padding, To make object conform to the word boundary of a machine. This is true for both C and C + +. In general, boundary adjustment (alignment) is determined by the processor (processor).
Concrete2 adds the only nonstatic data member Bit2, which has a datatype of char. The thoughtless programmer thought that it would be bundled with Concrete1, occupying the 1 bytes that had been used to fill the space; so Concreate2 The size of object is 8 bytes, where 2 bytes is used to fill space.
However, Concrete2 's bit2 is actually placed in the space to fill the 3 bytes after, so its size into a bytes, not 8 bytes. 6 of the bytes is wasted in filling space. The same reason that the size of the Concrete3 object is 16 Bytes, where 9 bytes are used to fill space.
Declare the following pointers:
Concrete2 *PC2;
Concrete1 *pc1_1, *pc1_2;
Where both Pc1_1 and pc1_2 can point to the aforementioned three classes of class object, the following specifies the operation:
*pc1_2 = *pc1_1;
You should perform a default "memberwise" copy operation (copy each of the members), which is the Concrete1 part of the object being referred to. If pc1_1 actually points to a Concrete2 object or Concrete3 Object, the above operation should assign the copied content to its Concrete1 subobject.
However, if the C + + language binds derived class member (that is, concrete2::bit2 or concrete3:;bit3) and Concrete1 subobject together, the fill space is removed. Those semantics cannot be preserved. Then the following specified action:
Pc1_1 = PC; Make pc1_1 point to Concrete2 Object
*pc1_2 = *pc1_1; Derived class subobject is covered
The "bundled, inherited" Members content is overwritten, and the programmer has to spend a great deal of effort to figure out the bug.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
C + + object Model--"inherit" with Data Member (chapter III).