C++ (inheritance, inheritance methods, friends, keywords)

Inheritance

Inheritance is an important feature of classes. Inheritance allows us to define another class based on one class, which makes it easy for us to create and maintain an application. A derived class will inherit all the methods of the base class. A type object acquires the properties and methods of another type object, with the following exceptions: base class constructors, destructors, and copy constructors. Overloaded operators for the base class. Friend function of the base class. The inherited template is as follows:

//The following is single inheritance
class <derived class name>: <inheritance mode 1> <base class name>
{<!-- -->
<derived class body>
}
//The following is multiple inheritance
class <derived class name>:<inheritance method 1><base class name 1>,<inheritance method 2><base class name 2>,…
{<!-- -->
<derived class body>
};

After inheritance, the subclass can rewrite the method of the parent class to achieve extended functions. Inheritance also has disadvantages: ①: The internal details of the parent class are visible to the subclass. ②: The method inherited by the subclass from the parent class is determined at compile time, so the behavior of the method inherited from the parent class cannot be changed during runtime. ③: If the method of the parent class is modified (for example, a parameter is added), the method of the subclass must be modified accordingly. Therefore, the subclass and the parent class are highly coupled, which violates the object-oriented thinking.
In addition to inheritance, another common method is combination. Combination is: when designing a class, add the object of the class to be combined to the class as its own member variable. Advantages of combination: 1. The current object can only call other methods through the contained object, so the internal details of the contained object are invisible to the current object. 2. The current object and the contained object have a low coupling relationship. If you modify the code in the class of the contained object, you do not need to modify the code of the current object class. 3. The current object can dynamically bind the contained objects at runtime, and can assign values to the contained objects through the set method. Disadvantages of combination: 1. It is easy to generate too many objects; 2. In order to combine multiple objects, the interfaces of different classes must be clearly defined.

public, private, protector

A feature of a class is encapsulation. We can access public members but not private members; private members can only be accessed by class members (inside the class) and friends, and cannot be accessed by derived classes; another feature of the class is to inherit protected The function is to achieve this purpose. Protected members can be accessed by derived class objects, but cannot be accessed by user code (outside the class).
Using public, private, and protected in inheritance will change the access attributes of base class members accordingly. The original attributes are public, private, and protected. Calling public inheritance attributes will become public, private, and protected; calling private inheritance attributes will change to It is private, private, private; call protected inheritance property to become protected, private, protected respectively.
The derived class contains all the members of the base class and new members. The members with the same name are hidden. When calling, only the members of the derived class will be called. If you want to call the members of the base class with the same name, you need to add upper scope.
In addition, C++ also has virtual inheritance. In the case of virtual inheritance, no matter how many times the base class is inherited, there will only be one entity, and a pointer will be added to the subclass to point to the subobject of the virtual base class or It points to a table (the address or offset of the virtual base class subobject is stored in the table). This pointer is called bptr. Some compilers will combine bptr and vptr into one pointer.

Friends

The purpose of a friend function is to allow a function or class to access private members in another class. The keyword for using a friend is friend. There are three implementation methods in total: using a global function as a friend, and using a class as a Friends, use member functions as friends. To set the global function as a friend, you need to declare the friend function in the class to be visited. For example, to use visit to visit the Building class, you need to set it like this:

class Building
{<!-- -->
// Tell the compiler that the laoWang global function is a good friend of the Building class and can access the private members of the Building object
friend void visit(Building *building);
...
};

A function can be a friend function of multiple classes, but this function must be declared in each class.
If you want to use setting a class as a friend, you first need to declare an access pointer variable in the class, and then declare the friend in the class you want to access:

class visit
{<!-- -->
public:
Building * building;
...
};
class Building
{<!-- -->
// Tell the compiler that the visit class is a good friend of the Building class and can access the private members of the Building class
friend class visit;
...
};

Using a member function as a friend is the same as using a class as a friend, you need to declare an accessed pointer variable Building *building in the class first, and then add it to the class to be accessed;

class Building
{<!-- -->
// Tell the compiler that the visit1() function under the LaoWang class is a good friend of the Building class and can access the private members of the Building
friend void visit::visit();
...
};

There are several points to note when using friend relations: 1) Friend relations cannot be inherited. (2) The friendship relationship is one-way and not exchangeable. If class B is a friend of class A, class A is not necessarily a friend of class B, depending on whether there is a corresponding statement in the class. (3) The friendship relationship is not transitive. If class B is a friend of class A, class C is a friend of B, class C is not necessarily a friend of class A, it also depends on whether there is a corresponding declaration in the class
References: Youyuan.

Keyword comparison

define and const: define works in the preprocessing stage of compilation, while const works in compilation and running; define only does replacement without safety check, does not check types and is prone to errors , and const constants have data types, and the compiler can perform security checks on them; define just replaces the macro name without allocating memory space, while const only allocates memory space because the value cannot be changed.
The difference between const and static Read this article.
final and override keywords: override is to specify that the virtual function in the subclass is to rewrite the parent class, so if the name of the function is wrong (there is no such virtual function in the parent class) Then the compiler will report an error usage virtual void foo() override; and final is when you don’t want a certain class to be inherited or you don’t want a certain virtual function to be rewritten, you can use it in the class name and virtual function After adding the final keyword, if it is inherited or rewritten after adding, the compiler will report an error class B final : A // indicates that B cannot be inherited, void foo( ) final; // At this time, if the subclass wants to use override to rewrite the function, an error will be reported.
volatile, mutable and explicit: The type declared by the volatile keyword can be changed by some factors unknown to the compiler. After encountering this keyword, the compiler will not optimize the code of the variable , which can provide stable access to special addresses. Volatile has several main functions:
1. After using volatile to declare a variable, the system always reads data from the memory where it is located, even if the previous instruction has just read data from there. The usage scenarios include (1) flags shared between tasks in a multi-tasking environment, (2) memory-mapped hardware registers are usually also described as volatile, because each read and write to it may have different meanings, (3) interrupt Variables modified in the service program for detection by other programs need to add volatile.
2. A volatile pointer is similar to a const. There are several points to note when using it (1) You can assign a non-volatile int to a volatile int, but you cannot assign a non-volatile object to a volatile object. (2) In addition to basic types, user-defined types can also be modified with volatile types. (3) A class with a volatile identifier in C++ can only access a subset of its interface, a subset controlled by the implementor of the class. Users can only use const_cast to gain full access to the type interface. Also, volatile, like const, is passed from a class to its members.
3, volatile under multi-threading, some variables are declared with the volatile keyword. When two threads will use a certain variable and the value of the variable will be changed, it should be declared with volatile. The function of this keyword is to prevent the optimizing compiler from loading the variable from memory into the CPU register. If the variable is loaded into the register, then two threads may use the variable in the memory and the variable in the register, which will cause the wrong execution of the program. Volatile means that the compiler must actually fetch it from memory every time it operates on the variable, instead of using the value already in the register.
mutable in Chinese means the variable root constant is an antonym. Mutable is set to break through the constraints of const. Variables modified by mutable are always in a variable state, even in a constant function, if the member function of the class Will not change the state of the object, then this member function will generally be declared as const. However, sometimes, we need to modify some data members that have nothing to do with the state of the class in the const function, then this function should be modified by mutable and placed in the keyword position after the function.

class person
{<!-- -->
int m_A;
mutable int m_B;//Special variables can also be modified in constant functions
public:
     void add() const//The value pointed to by this pointer cannot be modified in the function Constant pointer
     {<!-- -->
        m_A=10;//Error value cannot be modified, this has been modified as a constant pointer
        m_B=20;//Correct
     }
}
class person
{<!-- -->
int m_A;
mutable int m_B;//Special variables can also be modified in constant functions
}

explicit is used to modify the constructor of a class. The class of the modified constructor cannot undergo corresponding implicit type conversion, and can only perform type conversion in an explicit way. Note the following points: the explicit keyword can only be used for On the constructor declaration inside the class, the explicit keyword acts on the constructor of a single parameter, and the class of the constructor modified by explicit cannot undergo corresponding implicit type conversion (when you only have one type int, but the current expression requires For a value of type long, if int is automatically converted to long at this time, then this is an implicit type conversion.) For detailed implicit conversion, you can read this article to thoroughly understand implicit conversion.
The difference between macro definition and typedef: 1. Macro is mainly used to define constants and write complex content; typedef is mainly used to define type aliases. 2. Macro replacement occurs before the compilation stage, which belongs to text insertion and replacement; typedef is a part of compilation. 3. Macros do not check types; typedefs check data types. 4. A macro is not a statement, so do not add a semicolon at the end; typedef is a statement, and a semicolon should be added to mark the end. 5. Pay attention to the operation of pointers. There is a huge difference between typedef char * p_char and #define p_char char *. There are also differences between macro-defined functions and general functions: 1. Macros are replaced in the preprocessing stage, and then the replaced text participates in compilation, which is equivalent to directly inserting code. There is no function call at runtime, and the execution is faster; Function calls need to jump to the specific calling function at runtime. 2. The macro definition belongs to the code inserted in the structure and has no return value; the function call has a return value. 3. The macro definition parameter has no type, and no type check is performed; the function parameter has a type, and the type needs to be checked. 4. Do not add a semicolon at the end of the macro definition.