38. Never again define inherited default values.
Once again, defining a function's default value means defining the function again. Instead of a virtual function cannot be defined again, the reason why the default parameters of virtual functions cannot be defined again: Virtual functions are dynamically bound and the default values are statically bound.
A static type refers to a type declared in a program, whereas a dynamic type is the type of the actual object. Give me a chestnut:
Class a{public:virtual void Fun (int a=0) const{cout<<a<<endl;}}; Class b:public a{public:virtual void fun (int A =2) const{cout<<a<<endl;}}; int main () {b* PB = new B ();//pb static type is b*a* PA = pb;//pa static type is a*,//but a static type of a pointer is not necessarily a dynamic type, such as PA its dynamic type is a type B object, which is implemented by dynamic binding pb-& Gt;fun ();p a->fun ();
Virtual functions are dynamically bound. However, the default parameters are statically bound, that is, for the virtual function called by the PB,PA, the default values used are statically bound, the PA binds the a= 0 in Class A, and PB binds to the a=2 in Class B, which is different. Although the function is a virtual function that is dynamically bound in call B, the default number of parameters is different and the output is different.
39. Avoid the "downward transition" inheritance hierarchy.
A pointer to a derived class from a base class pointer is called a down conversion, typically using static_cast to cast a base-class pointer to a derived class pointer. The downward conversion is unsightly and easy causes errors. and difficult to understand, upgrade and maintain.
Elimination of down conversion: Replace with virtual function call. The first method is very easy to understand, but for some classes does not apply, such as the base class scope is too large to cause 7 of some derived classes should not have the function of the functions. Therefore, each virtual function of these classes is called an empty operation. Or as a pure virtual function. and the default implementation returns the wrong operation. The second method is to enforce the type constraint so that the pointer's declaration type is the same as the true pointer type you know.
That is, for these downward conversions, some settings are used. Filter out pointers that do not have a true pointer type. Simply leave a pointer that needs to be manipulated and invoke its function with its true type.
Suppose you encounter a need to convert, and do not use static_cast, but instead use a secure dynamic_cast for polymorphism, and when you use dynamic_cast on a pointer, try the conversion first. Assume that a valid pointer is returned successfully. Otherwise, a null pointer is returned.
40. By layering to reflect the "one" or "use." To achieve ".
Makes an object of a Class A data member that also has a class. This enables a class to be built on a class that is called a layered layering, also known as a composition, including or embedding.
For the concept of having a very easy to understand, for a person, there are attributes such as Name,address,phone, but can not say that the person is a Name.
For the "use.. To implement ", in fact, is to invoke other classes of objects as the main data members of the class, using the function of this class interface to implement the new class functions and interfaces.
41. Differentiate between templates and inheritance.
is distinguished by the purpose of the dependent class, such as if the dependent class is the behavior of the class, or if the dependent class is the object type to which the class operates, it is a template.
Such as. Penguins depend on birds, and the interface in birds determines the behavior of the Penguin class. That is, the two are inheritance, and when a collection is implemented, the collection class is dependent on the class T, because the class T is an object that operates on the collection class. This is the template.
The implementation of the template will be if the class is able to invoke functions such as the constructor assignment of T. The template's nature is that the behavior of the class template is not dependent on t anywhere. The behavior is not dependent on the type.
When the type of an object does not affect the behavior of a function in a class, a template is used to generate such a set of classes.
When the type of an object affects the behavior of a function in a class. Use inheritance to get such a set of classes.
42. Use private inheritance wisely.
Private inheritance is not a "is a" relationship. Assuming that the inheritance relationship between two classes is private, the compiler generally does not convert the derived class object to a base class object. When a private inheritance occurs, the members of the base class's public and protected types become private members of the derived class. Private inheritance means "with ... Implementation ". Private inheritance is purely an implementation technology.
Private inheritance is only an inheritance implementation, and the interface is ignored.
Private inheritance is meaningless in the software "design" process, only when the software is "implemented".
For layering, also useful ... The meaning of implementation, for hierarchical versus private inheritance, use hierarchies whenever possible. Private inheritance is used only if necessary.
It is recommended to use private inheritance when used to protect members and have virtual functions involved.
For a base class. Used only as implementations of other classes, using hierarchies as private members of other classes. But it is not an abstract class, causing it to be arbitrarily called by others causing an error. This is required to use private inheritance. For such a base class that has an implementation but can only be used for a specific purpose. Change its interface to the protected type. The class that uses it correctly does not need to be layered and uses private inheritance to safely use the base class.
For the template, it is one of the most useful parts of C + +, however, instantiating a template, it is possible to instantiate the code to implement this template, such as the code that makes up set<int> and set<double> is completely separate two code, the template will cause code bloat. Improved method: Create a generic class that stores void* pointers to objects. Create a set of classes to ensure type safety using the generic class. To implement stack stack as an example, first build a generic class for the stack:
Class GENERICSTACK{PROTECTED://Implementation classes use private inheritance to inherit this generic class, so the interface is protected genericstack (); ~genericstack (); void push (void* object); /Use pointer void* pop (); bool Empty () const;private:struct stacknode{void *data; Stacknode *next;//use pointers in the stack to pass data and save data, the node does not release the memory that the void pointer points to when it is refactored. Stacknode (void *newdata,stacknode *nextnode):d ata (NewData), Next (NextNode) {}}; Stacknode *top; Genericstack (const genericstack&);//Prevent copying and assignment genericstack& operator= (const genericstack&);};
The detailed class of the stack is implemented through the private inheritance of this class, and can use the template to complete the work perfectly:
Template <class t>class stack:private genericstack{public:void push (t* objectptr) {genericstack::p ush (objectPtr );} t* pop () {return static_cast<t*> (genericstack::p op ());} BOOL Empty () const {return genericstack::empty ();}};
Private inheritance is used here. The generic class genericstatck as a de facto, and its interface functions are inline functions, almost no consumption, and using templates to implement type-safe inference. For creating a random type of stack, it is only possible to compile this three simple inline function again, rather than a complex implementation in a generic class. Greatly reduces the cost of the program.
This code is amazing. Almost perfect.
The first use of the template, the compiler will be based on your need to actively generate all the interfaces. Because the template is used. These classes are type-safe and type errors can be found during compilation. Because the member function of Genericstack is a protection type, it is not possible for a user to bypass an interface class to invoke it.
Since the interface member functions of this template are implicitly declared inline. Using these classes does not lead to execution overhead, and generates code just like users write directly using Genericstack. Since Genericstack is using the void* pointer, the code for the Operation stack requires only one copy. The simple inline functions of the template are simply compiled by the different types.
In short, this design allows the code to achieve the highest efficiency and the highest type safety.
Effective C + + 38-42