1 OOP Overview
Object-oriented is based on three basic concepts: data abstraction, inheritance, and dynamic binding. Using data abstraction, we can separate class interfaces from implementations. Using inheritance, we can define similar types and model their similarity relationships. Using dynamic binding, to some extent, we can ignore the differences between similar types and use their objects in a unified manner.
1.1 inheritance
Inheritance is the relationship between the derived class and the base class. They share some common things, while the derived class features something actually different. The inheritance relationship between a class and a class constitutes an inheritance level. In C ++, the base class must specify which functions you want the derived class to redefine. A function defined as virtual is the base class that is expected to be redefined by the derived class, which must be inherited from a derived class cannot be defined as a virtual function.
Virtual can be added before a new virtual function defined by a derived class, but this is not necessary. In C ++ 11, A derived class is allowed to explicitly indicate which member function it will use to rewrite a base-class virtual function. You only need to add an override keyword after the parameter list in the form of this function.
1.2 dynamic binding
When a function interface defines a reference (or pointer) of a base class, dynamic binding occurs when a virtual function is called in the function. In this case, the function arguments can be of the base class type or a derived class type,Virtual functions are only in the running stage.To determine which definition to call.
2 define the base class and the derived class 2.1 define the base class
A base-class member function adds virtual to the function to be redefined in the derived class. This type of function is determined during the program running stage during the call. Non-static functions other than constructors can be virtual functions. Virtual keywords only need to be added before the function to be redefined when the base class is defined. This is not required during implementation.
A base class should usually define a virtual destructor, even if the function does not perform any actual operations.
A derived class can inherit the Members defined in the base class, but the member functions of the derived class cannot access the private Members inherited from the base class, and can only access the public and protected members. The user can only access the public members inherited from the base class through the derived class.
Pubic: Class Members accessible to users. inherited classes can also access them.
Private: the members and friends of the class can be accessed, but the inheritance class cannot.
Protected: the user cannot access it, but it can be accessed by a member of the class or a member of the derived class.
2.2 define a derived class
1) The member variables of a derived class are divided into two types: one is the member variables inherited from the base class, and the other is the variables that display their own special variables or those prepared for the special interface.
2) In general, all derived classes need to redefine the virtual functions declared in the base class, but if there is no redefinition, the definition in the base class will be extended.
3) The definition of the virtual function in the derived class should be exactly the same as that of the base class. If the base class returns a reference of the base class type, the derived class returns a reference of the derived class type.
4) when defining virtual functions in a derived class, virtual functions are not retained.
5) a class as a base class must have been defined, not just declaration, because its members will be used, so a class cannot derive a class from itself.
2.3 virtual and other member functions
Two conditions for dynamic binding:
1) virtual functions
2) base class type references or pointers for function calls
In any place where the base class is required, it can be replaced by a derived class object. Therefore, pointing to or referencing the base class can point to the derived class, because the derived class has all the members or member functions it needs.
The object is non-polymorphism-the object type is known and remains unchanged. The object's dynamic type is the same as the static type, which is opposite to the reference or pointer. The running function is defined by the object type.
If the derived class needs to call the base class version of the virtual function, the scope operator must be used to override the virtual function mechanism.
Do not define different default real parameters for virtual functions in the base class and derived class, because the real parameters are statically bound and determined during compilation, therefore, when you use a pointer to the base class type of the derived class object to access the virtual function, you actually use the default real parameters of the base class member function.
2.4 access control and inheritance
The access label used in the derived list is used to determine the user who uses the derived class and the permission to access the base class members.
First, only the public and protected members in the base class can be accessed by the derived class.
1) if the derived class is public inheritance)
Members or friends of a derived class can access the public and protected members in the base class. Users can access the public members in the base class through the derived class. The private in the base class can only be accessed by members of the base class.
Class Bulk_item: public Item_base {...};
The public and protected types in the base class are the same as those in the derived classes.
2) If the derived class is protected inheritance (protected inheritance)
Class Bulk_item: protected Item_base {...};
The public and protected members in the base class are like the protected members in the derived class.
3) if the derived class is private inheritance)
Class Bulk_item: private Item_base {...};
The public and protected members in the base class are like the private members in the derived class. You cannot access any Members in the base class through the derived class object.
The public derived class inherits the interface of the base class. You can use the public derived class where the base class is required. Private and protected Derived classes are not allowed.
You can use the using statement to restore the access level of the base class members in the derived class.
Class and struct define inherited classes. The default inherited classes are also different.
Class Base {...};
Class D1: Base {...} is equivalent to class D1: private Base {...}
Struct D2: Base {...} is equivalent to class D2: public Base {...}
The class and struct are used to define the class except the access level.
The member functions of the derived class cannot directly access the protected of the base class object.Member, but you can access the protected of the base class through the derived class object.Member.
void Bulk_item::memfcn(const Bulk_item &d, const Item_base &b){ // price is protected double ret = price; //ok ret = d.price;//ok ret = b.price;//error}2.5 inheritance and static members
If the base class defines static members, there is only one such member in the entire inheritance hierarchy.
2.6 prevent inheritance
Sometimes we define such a class. We do not want other classes to inherit it, or do not want to consider whether it is suitable as a base class. In C ++ 11, a keyword final can be added after the class name to prevent inheritance.
Class NoDerived final{/* */ }Class Bad : public NoDerived{/* */ } // error!3 Conversion between a derived class and a base class
A base class pointer or reference can be bound to a derived class object, which has an extremely important meaning: When a base class reference (or pointer) is used, in fact, we do not know the actual type of the object to which the reference (or pointer) is bound. This object may be a base class object or a derived class object.
3.1 static and dynamic types
The static type of the expression is always known during compilation. It is the type generated by the type or expression during variable declaration. The dynamic type is the type of the object in memory represented by the variable or expression, the dynamic type is not known until it is run. If the expression is neither a reference nor a pointer, its dynamic type will always be consistent with the static type.
3.2 convert a derived class to a base class
Reference conversion is different from object conversion.
1) Pass the derived class object to the function that you want to accept the base class reference. In fact, the original derived class object is passed in, and this object has not changed.
2) if you pass the derived class object to a function that wants to accept the base class object, it actually copies the base class part of the object of the real-name derived class and creates a temporary base class object.
3) The conversion from a derived class object to a base class object is actually like a "cropping" operation.
3.3 convert a base class to a derived class
There is no (automatic) conversion from the base class type to the derived type, because the derived class may contain no members in the base class. Even when the base class pointer or reference is actually bound to a derived class object, conversion from the base class to the derived class also has restrictions.
Bulk_item bulk;Item_base *itemP = &bulk; // okBulk_item *bulkP = itemP; // error
4. Virtual Functions
1) The fact that the reference or pointer's static type is different from the dynamic type is exactly the root of the C ++ language support polymorphism.
2) the virtual function in the base class is implicitly a virtual function in the derived class. When a derived class overwrites a virtual function, the parameters of the function in the base class must match those in the derived class.
3) it can be the form parameter of the function. The override is added after the table, indicating that the function is a virtual function in the derived class, and the final is used to indicate that you do not want to overwrite the function in the inheritance class.
4) if a virtual function of a derived class needs to call its base class version but does not use the scope operator, the call will be resolved to its own call at runtime, this leads to infinite recursion.
double undiscounted = baseP->Quote::net_price(42);
5) If we call a function through a base class reference or pointer, the default real parameter defined in the base class is used, even if the function version in the derived class is actually used.
5. abstract base class
1) adding = 0 to the parameter table of the virtual function will convert the virtual function to a pure virtual function. The pure virtual function itself does not need to be defined, it only provides an interface for the derived class to represent the abstract universal meaning. It is worth noting that we can also provide definitions for pure virtual functions, but the function body must be defined outside the class.
2) classes that contain (or inherit directly without overwriting) pure virtual functions are abstract base classes. The abstract base class defines the interface, and other classes can overwrite the interface. We cannot define an abstract base class object.
3) The derived class constructor only initializes its direct base class.
class Disc_quote :public Quote{public: Disc_quote() = default; Disc_quote(const string& book, double price, size_t qty, double disc) : Quote(book, price), quantity(qty), discount(disc){} double net_price(size_t)const = 0;protected: size_t quantity = 0; double discount = 0.0;};class Bulk_quote :public Disc_quote{public: Bulk_quote() = default; Bulk_quote(const string &book, double price, size_t qty, double disc) : Disc_quote(book, price, qty, disc){} double net_price(size_t)const override;};6. Class scope under Inheritance
1) Name Search occurs in the compilation phase. That is to say, objects, pointers, and references can only access Members of Their static types.
2) When the derived class defines members with the same name as the base class, the base class members will be blocked. Of course, they can be accessed using the scope operator.
3) functions with the same name defined in the derived class are blocked even if the form parameters are different. The same principle: functions defined in local scopes Do not overload the functions defined in global scopes.
4) if you want the derived class to use all the overload members, either not defined or fully defined in the derived class.
7. constructor and replication Control
Because the derived class actually contains some members of the base class, this will affect the construction, copying, moving, assigning, and revoking of the derived class.
7.1 constructor and inheritance
Constructor and replication Control Members cannot inherit. Each class must have its own constructor and replication control members.
However, in C ++ 11, a derived class can be directly defined with its base class constructor, but it is also limited to this. It still cannot inherit the default, copy, or move constructor.
The derived class inherits the base class constructor by providing a using declaration statement with the base class name specified. In this way, for each constructor of the base class, the compiler generates a constructor of the corresponding derived class.
Class Bulk_qute: public Disc_quote {public: using Disc_quote: Disc_quote; // inherits the Disc_quote const ;};
If the constructor defined by the derived class has the same parameter list as the base class constructor, the constructor will not be inherited.
7.2 construction and replication control functions of base classes
The construction and replication functions of the base class are basically not affected. The only effect is that when determining which constructor should be used, you can add protected before the constructor, so that it can only be used in a derived class.
7.3 constructor of a derived class
1) default constructor of the synthesized derived class
Two steps: 1. Call the default function of the base class to initialize the base class members; 2. Use the general variable initialization rules to initialize the special members of the derived class.
2) define the default constructor
You can assign an initial value to only the special member of the derived class, and the function implicitly calls the constructors of the base class to define the base class members.
3) passing real parameters to the base class Constructor
The constructor initialization list of a derived class. You Cannot initialize the derived members directly. You can only include the base class in the initialization list to indirectly initialize those members.
Bulk_item(const string& book, double sales_price, size_t qty = 0, double disc_rate = 0) : Item_base(book, sales_price), min_qty(qty), discount(dis_rate){}
4) only the direct base class can be initialized
In the case of multi-inheritance, the constructor of a derived class can only initialize its own direct base class.
5) respect the basic interface
Although you can directly access the public and protected members of the base class in the constructor body of the derived class for initialization, do not do this, but use the constructor interface provided by the base class.
7.3 copy control and inherit 7.3.1 define the copy constructor of the derived class
If the derived class explicitly defines its own copy constructor or value assignment operator, this definition will completely overwrite the default definition. The base class must also be completed by the function defined by the derived class, and cannot be implicitly copied or assigned (this is different from the constructor ).
In the copy constructor of a derived class, the base class's copy constructor is explicitly called. Because its form parameter is a reference of the base class type, you can directly pass the derived class object as a real parameter.
If no explicit call is made, the default constructor of the base class is called implicitly to complete the definition of some members of the base class. In this way, the final derived class object is very strange.
7.3.2 value assignment operator of a derived class
Similar to the copy constructor, you must explicitly call the assignment function of the base class.
Derived& Derived::operator=(const Derived &rhs){ if (this != &rhs) { Base::operator=(rhs); // then do } return *this;}7.3.3 destructor of a derived class
The derived class destructor is not responsible for revoking the member of the base class object. The compiler always explicitly calls the destructor of the base class of the derived class object. Each destructor is only responsible for clearing its own members.
7.3.4 virtual destructor
Item_base *itemP = new Item_base;delete itemP;itemP = new Bulk_item;delete itemP;
In the code above, when delete points to the class pointer, The Destructor will be called, But here itemP may point to the base class or to the derived class, therefore, different types of destructor should be called in the running phase.
Therefore, the destructor of the base class are virtual functions: virtual ~ Item_base (){}
7.3.5 call virtual functions in constructor and destructor
The version is defined for the constructor or destructor type.