Reading Notes Objective c ++ Item 36 never redefines the inherited non-virtual functions.
1. Why not redefine the inherited non-virtual functions-actual arguments
Suppose I tell you a Class D public inherits Class B and defines a public member function mf in Class B. Mf parameters and return types are not important, so assume they are all void. The implementation is as follows:
1 class B {2 public:3 void mf();4 ...5 };6 lass D: public B { ... }
We do not need to know any details about B, D, or mf. Consider an object x of the type D,
1 D x; // x is an object of type D
You will be surprised if the following statement:
1 B *pB = &x; // get pointer to x2 3 pB->mf(); // call mf through pointer
Different from the following statement
1 D *pD = &x; // get pointer to x2 3 pD->mf(); // call mf through pointer
In both cases, you trigger the member function mf of object x. Because the two cases use the same object and the same function, the behavior should be the same, isn't it?
This should be the case. But it may not. In particular, if mf is a non-virtual function and D defines its own mf version, the above behavior will be different:
1 class D: public B { 2 public: 3 void mf(); // hides B::mf; see Item 33 4 5 ... 6 7 }; 8 pB->mf(); // calls B::mf 9 10 pD->mf(); // calls D::mf
The reason for this two-sided behavior is that non-virtual functions such as B: mf and D: mf are statically bound (statically bound Item37 ). This means that because pB is declared as a pointer to B, all non-virtual functions triggered by pB are defined on Class B, even if pB points to the derived class object of B, that is, the implementation in this example.
Virtual functions are dynamically bound (dynamically boundItem 37), so they do not have the above problems. If mf is a virtual function, calling mf through pB or pD triggers D: mf, because pB or pD actually points to the object of Type D.
If you implement a Class D and redefine the non-virtual function mf inherited from Class B, the D object will also exhibit inconsistent behavior. In particular, the act of calling the mf function through the D object may be like B or D, and the object itself is not a deciding factor. The deciding factor is the pointer type pointing to the D object. The behavior shown by the reference is the same as that of the pointer.
2. Why not redefine the inherited non-virtual functions-Theoretical Arguments
The above is only a practical demonstration. I know what you really want to know is the theoretical proof that "do not redefine the inherited non-virtual functions. See the following analysis:
Item 32 explains that pulibc inheritance means "is-", item34 describes why a non-virtual function is defined in a class as an immutable (invariant overspecialization ). If you apply these observations to Class B or Class D and non-virtual member function B: mf, you will find:
- Everything applied to Class B can also be applied to Class D, because every D object is a Class B object.
- Classes derived from Class B inherit both the interface and implementation of mf, because mf is a non-virtual function in Class B.
Now, if D re-Defines mf, there will be a conflict in your design. If D really wants to implement a mf different from B, and if every B object -- no matter how special -- must actually use B for mf, every D object is a B object. In this case, D should not inherit from B. In another aspect, if D must be public inherited from B, and D must implement a mf different from B, then, the extra immutability of mf for B is no longer true. In this case, mf should be virtual. Finally, if every D is actually a B, and if mf is actually a special immutability for B, then D really does not need to be redefined, you shouldn't try this either.
No matter which point of view or conclusion is the same, it is prohibited to redefine an inherited non-virtual function.
3. You should be familiar with the terms.
If you read this clause, it may be because you have read Item7. This clause explains why the virtual function in the polymorphism base class should be virtual. If you violate the terms in Item7 (that is, you declare a non-virtual destructor in the polymorphism base class), you will also violate the terms, because the derived class will always redefine the inherited non-virtual function: The destructor of the base class. This is true for a derived class without a defined destructor, because, as explained in Item 5, if you do not declare the Destructor yourself, the compiler will automatically generate one for you. In essence, Item7 is only a special case of this clause, although it is important enough to become a separate clause.
4. Summary
- Never redefine an inherited non-virtual function.