Effective C++ notes (below)

Chapter 6 Inheritance and Object-Oriented Design

This chapter discusses how object-oriented programming (OOP) in C++, and introduces OOP in C++ from the aspects of inheritance, derivation, and virtual functions.

Item 32: Make sure your public inheritance molds the is-a relationship

"Public inheritance" means the is-a relationship. Everything that applies to base classes must also apply to derived classes, because every derived class object is also a base class object.
Is-a (belongs to), has-a (contains), and is-implemented-in-terms-of (implemented based on something) are three common relationships between classes.

Article 33: Avoid obscuring the inherited name

  1. The names in derived classes will obscure the names in base classes. No one has ever hoped that under the public inheritance. That is, members of the derived class will override the members of the same name in the base class.
  2. You can use using declarative or transfer functions to avoid name masking. Using declarative: Expose all members of the specified name that are obscured in the derived class; transfer function: call a specific member function with the same name in a function in the derived class.

Item 34: Distinguish between interface inheritance and implementation inheritance

  1. Interface inheritance is different from implementation inheritance. Under public inheritance, the derived class always inherits the interface of the base class. (What about private inheritance?)
  2. The pure virtual function only specifies interface inheritance. (The derived class must supplement the function implementation)
  3. The impure virtual function specifies interface inheritance and default implementation inheritance.
  4. The non-virtual function specifies interface inheritance and mandatory implementation inheritance. (Non-virtual functions can be overridden by derived classes, but they do not conform to the principles of oop)
  5. Do not arbitrarily declare all functions as non-virtual, and do not arbitrarily declare all functions as virtual.

Item 35: Consider alternatives to virtual functions ( Difficult to understand, let’s briefly summarize

  1. Use the non-virtual interface (NVI) technique to wrap the lower-access (private or protected) virtual functions with public non-virtual member functions.
  2. Use "function pointer member variables" to replace virtual functions.
  3. Replace the virtual function with tr1::function member variable.
  4. Replace the virtual function of the inherited system class with a virtual function in another inherited system.

Item 36: Never redefine inherited non-virtual functions

Public inheritance means the "is-a" relationship. The non-virtual function indicates that the interface and implementation should be inherited, and redefining the function is wrong.

Item 37: Never redefine inherited default parameter values

Never redefine an inherited default parameter value, because the default parameter values ​​are statically bound, and virtual functions—the only thing you should override—are dynamically bound.
Supplement: The static type of an object refers to the type used when it is declared in the program; the dynamic type refers to the "type of the object currently referred to". Static binding is to call the function of the static type of the object, and dynamic binding is to call the function of the dynamic type.

class Base
{
    
    
...
};
class Derived:public Base
{
    
    
...
}
Base *pb; //pb的静态类型为Base,无动态类型
Base *pd = new Derived;	//pd的静态类型为Base,动态类型为Derived

Clause 38: Has-a or "realized based on something" through compound molding

  1. Composition is a relationship between types, which means that a certain type of object contains other types of objects. Also called layering, inclusion, aggregation or embedding.
  2. In the application domain, composite means has-a (there is one) . In the realization domain, composite means is-implemented-in-terms-of (implemented according to something) .

Item 39: Use private inheritance wisely and judiciously

  1. Private inheritance means is-implemented-in-terms of. It is usually lower than the level of composition. But when the derived class needs to access the members of the protected base class, or need to redefine the inherited virtual function, this design is reasonable.
  2. Unlike compounding, private inheritance can optimize the empty base space. This may be important for library developers who are committed to "minimizing object size."

Item 40: Use multiple inheritance wisely and judiciously

  1. Multiple inheritance is more complicated than single inheritance. It may lead to new ambiguities and the need for virtual inheritance.
  2. Virtual inheritance will increase the size, speed, initialization (and assignment) complexity and other costs (because virtual inheritance will make the derived class object contains a virtual base table pointer). If virtual base classes do not carry any data, it will be the most practical value.
  3. Multiple inheritance has legitimate uses. One of the plots involves a combination of "public inherits an interface class" and "private inherits a class that assists in implementation".

Chapter 7 Templates and Generic Programming

The focus of this chapter is how to better program based on template.

Item 41: Understand implicit interfaces and compile-time polymorphism

  1. Both classes and templates support interfaces and polymorphism.
  2. For classes, the interface is explicit, centered on the function signature. Polymorphism occurs at runtime through virtual functions.
  3. For template parameters, the interface (all possible functions in the template) is implicit and based on valid expressions. Polymorphism occurs at compile time through template realization and function overload resolution.

Item 42: Understand the dual meaning of typename

  1. When declaring template parameters, the prefix keywords class and typename are interchangeable.
  2. Please use the keyword typename to identify the name of the nested subordinate type; but it must not be used as the base class modifier in the base class lists or member initialization list.

Item 43: Learn to handle names in templated base classes

When deriving from base class templates, derived class templates cannot directly access the name of base class templates as in object-oriented programming. Because the derived class templates definition formula cannot determine what kind of class the inherited base class is at compile time, or even whether the base class contains the accessed name, the compiler refuses to enter the base class template to look for inherited ones. name. There are three ways to solve this problem in the article:

  1. Add "this->" before the base class function call action
  2. Use the using declarative to tell the compiler the base class of the name used
  3. Clearly write "base class qualification modifier" before the name (but it will turn off the virtual binding behavior)

Item 44: Remove code that has nothing to do with parameters from templates

  1. Templates generate multiple classes and multiple functions, so any template code should not be dependent on a template parameter that causes inflation (extract the part that will generate the same code after the template is realized).
  2. Code bloat caused by non-type template parameters (representing parameters other than types) can often be eliminated by replacing template parameters with function parameters or class member variables.
  3. The code expansion caused by type parameters (parameters that represent types) can often be reduced by sharing implementation codes with actual types with exactly the same binary representation.

Item 45: Use member function templates to accept all compatible types

  1. The meaning of type compatibility is to support type conversion. In order to make the template class support type compatibility, member function templates need to be used in the template class, so that when the template class is realized, a function that "accepts all compatible types" can be generated.
  2. If we declare that the member template is used for "generalized copy constructor" or "generalized copy assignment operation", then we still need to declare the normal copy constructor and copy assignment operator, otherwise the compiler will complete this task for us.

Item 46: When type conversion is required, define non-member functions for the template (Hard to understand

When we write a class template, and the "template-related" functions it provides need to support "all parameters can be implicitly converted", please define these functions as "friend functions inside the class template".
The key point of this problem is that "the member functions in the class template do not support implicit conversion of the actual parameters to the class type represented by the template". (I didn't fully understand the explanation of this question, so skip it first)

Item 47: Please use traits classes to express type information

  1. Traits classes (extractors) make "type-related information" available at compile time. They are implemented in templates and "templates specialization".
  2. After integrating the overloading technology, traits classes may perform if...else tests on types during compile time.
  3. How to design and implement a traits class: first confirm the type-related information we hope to be available in the future; choose a name for the information; provide a template and a set of specialized versions that contain the type-related information you want to support.
  4. How to use a traits class: first create a set of overloaded functions (labor functions) or function templates, the difference between each is only in their traits parameters, so that each function implementation code and the traits information it accepts correspond to; then establish a control Function (foreman function) or function template, which calls the above-mentioned "labor functions" and passes the information provided by the traits class.

Item 48: Recognize template metaprogramming (Suitable for intermediate and advanced programmers

  1. Template metaprogramming (template metaprogramming) can move the work from runtime to compile time, thus enabling early error detection and higher execution efficiency.
  2. TMP can be used to generate customized codes "based on policy selection combinations", and can also be used to avoid generating codes that are not suitable for certain special types.

Chapter 8 Customizing new and delete

Let's get an idea

Item 49: Understand the behavior of the new-handler

The new-handler is an error handling function designated by the customer when the memory requirement of the operator new cannot be satisfied. The new-handler will be called in a loop until the dynamic memory is successfully allocated. The new-handler can be set by the standard library function set_new_handler.

Article 50: Reasonable timing of replacement of new and delete

  1. To detect application errors;
  2. To collect usage statistics of dynamically allocated memory;
  3. In order to increase the speed of distribution and return;
  4. In order to reduce the space overhead caused by the default memory manager.
  5. In order to compensate for the non-optimal alignment in the default allocator.
  6. In order to cluster related objects.
  7. In order to obtain non-traditional behavior.

Item 51: Stick to conventions when writing new and delete

Item 52: Write placement delete if you write placement new

Guess you like

Origin blog.csdn.net/gaggagaasd/article/details/108906201