Knowledge points in this section: 1. Function Rewriting: a. Through the previous article We can know, Subclass and parent class can define member variables with the same name, The subclass still inherits the variable with the same name in the parent class., By default, the member variables with the same name in the subclass hide the member variables with the same name in the parent class., If you want to access the member variables with the same name as the parent class, use the respective scopes symbol.. B. Member functions with the same name in the subclass and parent classes:First, When function parameters are the sameThis occurs between the subclass and the parent class. Except for the function body, the prototype is exactly the same function. This is called Function Rewriting. For rewriting, the member functions with the same name in the subclass will hide the member functions with the same name in the parent class. To call the member functions with the same name in the parent class, use the respective scopes symbol. Note: function rewriting only occurs between the parent class and the subclass.Second, Function parameters are different, Remember, In this case, function rewriting is not performed, and function Overloading is not performed (there is no overload between the subclass and the parent class), but because the function name is the same, the function in the subclass hides the member functions with the same name in the parent class. To sum up, if a member of the same name exists in the subclass and parent classes, the member in the subclass hides the member in the parent class. The member functions with the same name are the same as those with the same name. A member function with the same name with the same function parameters will be overwritten.Sample Code:
# Include
Using namespace std; class parent {public: void fun (int a) // these two functions are overloaded {cout <"parent fun () "<a <endl;} void fun () {cout <" parent fun () "<endl ;}}; class child: public parent {public: void fun () // rewrite {cout <"child fun ()" <endl ;}; int main () {child c; with the function in the parent class above; c. parent: fun (4); // here the function overload c. parent: fun (); c. fun (); // function rewriting hides functions with the same name in the parent class. // c. fun (4); // here an error is reported because the function of the function overload quilt class hides return 0 ;}
C. The function to be rewritten in the parent class will still inherit from the Child class, but the function in the quilt class is hidden. However, you can use the scope identifier: To access hidden functions in the parent class. 2. compatibility between function rewriting and assignment:. for the compatibility of class assignment, the pointer or reference of the parent class points to the subclass object, for example, parent * p = & c or parent & p = c
In this case, p cannot access the unique members in the subclass. It can only access the members inherited from the parent class to the subclass.. In fact, it should be
Hides a process similar to forced type conversion.,
Just like assigning an int variable to a char variable.,
The.
If a member with the same name exists between the parent class and the subclass, all members with the same name of the parent class can be accessed (provided that no virtual function is set).
When p accesses, it first determines whether the access member inherits the parent class to the subclass. If no, an error is reported directly, indicating that the member does not exist (because the p type is parent ). Then determine whether the parent class subclass has the same name directly. If the child class has different names, the Child class will be assigned a value to the parent class. A member of the same name in the parent class is called directly to ignore the member in the subclass.Sample Code:
#include
using namespace std;class parent {public:int a;int b;void fun(){cout << "parent fun " << endl;}};class child : public parent{public:int a;void fun(){cout << "child fun " << endl;} };int main(){child c;c.a = 10;c.b = 100;parent *p = &c;parent &p1 = c;cout << p->a << endl;cout << p1.a << endl;cout << p1.b << endl;cout << p->b << endl;p->fun();p1.fun();return 0;}
Note:
If the child class and the parent class have members of the same name, the child c subclass object accesses members of the same name, hide members of the same name inherited from the parent class (this is the type of the Child class ). If a parent class pointer or a reference pointing to a subclass object has a member of the same name, it must be a member of the same name of the parent class accessed through a pointer or reference, the member with the same name of the subclass is not hidden, but is not assigned a value at all (this is the type of the parent class ). Here is a problem. The type of the variable determines the behavior of the variable !!! (But the premise must be that no virtual function is set)
B. Both c language and c ++ Language
Static compilation language,
The so-called static compilation language is to clear the type of the variable function before compilation, and compile according to the determined type of the variable function.Therefore, by default, because the program is not running, it is impossible to know whether the parent class Pointer Points to a parent class object or a subclass object, all parent class pointers point to parent class objects. Therefore, the compilation result is to call the member functions of the parent class. 3. The essence of polymorphism:.
How to judge the calling of rewrite functions based on different object types is a concept of polymorphism in object-oriented systems. If the parent class Pointer Points to a parent class object, the function defined in the parent class is called. If the parent class Pointer Points to a subclass object, the rewrite function defined in the subclass is called.B. polymorphism,
Determines the specific call target of the function call statement based on the actual object type.It breaks the drawbacks of c ++ static compilation.
So that the same call statement has a variety of different forms.
C. Use virtual functions to enable the rewritten functions to have polymorphism.
In c ++, polymorphism is supported by the virtual keyword. After the virtual declared function is overwritten, The polymorphism feature can be displayed.Sample Code:
# Include
Using namespace std; class parent {public: virtual void fun () {cout <"parent fun ()" <endl ;}}; class child: public parent {public: virtual void fun () {cout <"child fun ()" <endl ;}}; int main () {child c; parent * p = & c; p-> fun (); // The same statement has different forms of parent d; p = & d; p-> fun (); // return 0 ;}
NOTE: For the declaration of virtual functions, you only need to declare them in the parent class and do not need to declare them in the subclass. It can also be declared in the parent class or in the subclass.4. Rewriting and overloading: a. Some concepts should be explained before rewriting and overloading.
In a class, functions or variables with the same name are certainly not allowed.. However, although the Child class is a special parent class between the parent class and the Child class object, they are relatively independent after all,
In this way, a member with the same name exists between the subclass and the parent class.,
Meanwhile, the subclass also hides members of the parent class with the same name by default..
Subclass still inherits members of the parent class with the same name,
You can access the service by using the specific scopes..
For a member function with the same name, there are two cases where function rewriting occurs if the same parameter is used. If the parameters are different, remember that there is no overload here (because there is no overload between the subclass and the parent class). Although the parameters are different, they are two completely different functions, however, if the function name is the same, it is hidden. The difference between the two is that function rewriting allows the parent class and the Child class to have exactly the same function structure. In short, c ++ allows the existence of identical member functions (that is, function rewriting) and member variables with the same name between the subclass and the parent class, different member functions with the same name are also allowed (which is reasonable in fact), but function Overloading is not required. All members with the same name are hidden from the parent class, and can be accessed through the scopes.B.
Compare and override:Function overload:
It must be in the same scope. The Child class cannot overload the parent class function, and the function with the same name of the parent class will be hidden. During the compilation, the overload decides which function to call based on the parameter type and quantity statically.Function Rewriting:
It must occur between the parent class and the subclass. In addition, the function between the parent class and the subclass must have the same function prototype. Polymorphism can be generated after the virtual keyword is declared. Polymorphism dynamically calls a function during running based on the type of the specific object.5. deep understanding of virtual functions:.
Implementation principle of polymorphism in c ++:When a virtual function is declared in a class, the compiler generates a virtual function table in the class. A virtual function table is a storage class member virtual function.
Function pointerIs actually
Linked List).
The virtual function table is automatically generated and maintained by the compiler. Virtual member functions are written into the virtual function table by the compiler. When a virtual function exists, each object has a pointer to the virtual function table (VPTR pointer)
B.
Implementation of polymorphism: first,
There must be more than two classes with inheritance relationships (one parent class and multiple child classes are a classic example).
Then,
There is a function rewrite between classes. Then, define the rewritten function as a virtual function. Because virtual member functions are defined, the compiler will generate their own virtual function tables when these classes create objects. Of course, each virtual function table needs the pointer of its own virtual function table (VPTR pointer is a member of the class and the first member ). Most importantly, when calling polymorphism functions, the compiler first checks whether the function is a virtual function. If yes, use the virtual function table pointed to by the VPTR pointer of the object at this time to find this function and call it, the search and call are completed when the program is running (note how the VPTR pointer is found for the object. This pointer cannot be called by the outside world first. When a function is declared as a virtual attribute in the class, there will be one more member variable in the class, that is, the VPTR pointer, and this pointer is placed at the first member of the class, that is, the object address is the VPTR pointer address, when an object is created, that is, the virtual function table of the object is created after the class constructor is called. At this time, the VPTR pointer is assigned a value, point it to the virtual function table of the object ). If not, the compiler can directly call member functions of this type.
Sample Code:
# Include
Using namespace std; class parent {public: int a; virtual void fun () {cout <"parent fun ()" <
Fun (); return 0 ;}
Note:
For efficiency, it is not necessary to declare all member functions as virtual functions.The virtual function table pointer VPTR is used to call the rewrite function in
When the program is running,
Therefore, the addressing operation is required to determine the actually called function.. While common member functions
The called function is determined during compilation.. In terms of efficiency,
The efficiency of virtual functions is much lower.C. Relationship between virtual functions and Polymorphism:
Polymorphism is implemented by virtual functions. But even if I don't want to implement polymorphism, I can still define virtual functions in the class. When the class creates an object, the virtual function table is still generated, and the VPTR pointer still exists.
D. when an object is created, the VPTR pointer is initialized by the compiler. The VPTR pointing to the parent class object is final only after the object structure is complete. The VPTR of the parent class object points to the parent class virtual function table, the VPTR of the subclass object points to the virtual function table of the subclass.
E. Unable to realize polymorphism when calling virtual functions in constructor: this is a question in this section. If a great God passes by, I hope the great God will give you some advice. I also hope that I can add it to my later study !!! The relationship between the constructor and the VPTR pointer of instructor Tang (the whiteboard diagram of instructor Tang) and the example of this pointer (the Code of instructor Tang ), I keep it !!! To be improved later !!! There is an incorrect counterexample. The Code is as follows:
#include
using namespace std;class parent{public:parent(){cout << "hello parent()" << endl;}virtual void fun(){cout << "parent fun() " <
fun();}void fun(){cout << "child fun() " << endl;}}; int main(){parent p;child c(&p);child c1(&c);}
Although you are not sure, remember that the constructors cannot use virtual functions to complete polymorphism.
6. Pure virtual function: a. abstract class in Object-Oriented architecture:
Abstract classes can be used to represent abstract concepts in the real world.
An abstract class is a class that can only define types but cannot generate objects.
Abstract classes can only be inherited and rewritten. The direct feature of an abstract class is a pure virtual function.B. Pure virtual functions:
Declare only the function prototype, and deliberately do not define the virtual function of the function bodyC. abstract classes and pure virtual functions: 1:
Abstract classes cannot define objects (because abstract classes use inheritance to overwrite pure virtual functions of their parent classes so that multiple sub-classes can generate polymorphism ), abstract classes are not intended to create objects, but to make subclasses produce polymorphism.Second:
An abstract class can only define pointers and references.Third:
The pure virtual function in the abstract class must be overwritten by the quilt class.Fourth:
Because pure virtual functions exist, classes become abstract classes. Because pure virtual functions do not have function bodies and cannot be called, abstract classes cannot define objects, is to rewrite the function of the subclass of the abstract class to realize polymorphism.) When the abstract class defines an object, it is possible to call pure virtual functions!D. Examples of pure virtual functions:
class shape{public:virtual double area() = 0;};
NOTE: If area is a pure virtual function, = 0 indicates that this function is a pure virtual function and only declares that the function body is not defined.
Sample Code (this is an example of a good abstract class and a good example of polymorphism ):
#include
using namespace std;class Shape{public: virtual double area() = 0;};class Rectangle : public Shape{ double m_a; double m_b;public: Rectangle(double a, double b) { m_a = a; m_b = b; } double area() { return m_a * m_b; }};class Circle : public Shape{ double m_r;public: Circle(double r) { m_r = r; } double area() { return 3.14 * m_r * m_r; }};void area(Shape* s){ cout<
area()<