Explain the conversion of base class and derived class in C + + and the virtual base class _c language

Source: Internet
Author: User
Tags inheritance

C + + base class and derived class conversions
In public inheritance, in private inheritance and protection inheritance, only public inheritance can preserve the characteristics of the base class, it retains all members of the base class except constructors and destructors, and the access rights of the public or protected members of the base class are all preserved as is in the derived class, You can call the public member function of the base class outside the derived class to access the private members of the base class. Therefore, a public derived class has all the functionality of a base class, and the functionality that all base classes can implement can be implemented by common derived classes. Instead of a public derived class (private or protected derived), you cannot implement the full functionality of the base class (for example, you cannot call a public member function of a base class outside of a derived class to access a private member of the base class). Therefore, only a public derived class is a true subtype of the base class, and it inherits the functionality of the base class.

Different types of data can be converted under certain conditions, such as integer data can be assigned to a double variable, before the assignment, the integer data into the double data, but can not assign an integer data to the pointer variable. This automatic conversion and assignment between different types of data is called assignment compatibility. The question now to be discussed is whether the base class and derived class objects also have assignment-compatible relationships, can you convert between types?

The answer is OK. There is an assignment-compatible relationship between the base class and the derived class object, because the derived class contains members that inherit from the base class, so the value of the derived class can be assigned to the base class object and can be substituted with its subclass object when the base class object is used. Specific performance in the following aspects.

1 derived class objects can assign values to base class objects

You can assign a value to its base class object with a subclass (that is, a public derived class) object. Such as

  A A1; Defines the object B1 a1=b1 of the base Class A object A1
  B b1;//definition of the public derived class B of Class A
  ; B1 assignment to a base class object with a derived Class B object A1


Discard the derived class's own members when assigning values. Which is "overqualified", as pictured

In fact, assignment is only assigned to data members, and no assignment problems exist for member functions.

Note that when you assign a value, you cannot attempt to access the members of the derived class object B1 through the object A1 because the B1 members are different from the members of the A1. If age is a public data member that is added in derived class B, analyze the following usage:
a1.age=23; Error, A1 does not contain the added member in the derived class
b1.age=21; Correct, the B1 contains the added members of the derived class

It should be noted that subtype relationships are one-way and irreversible. B is a subtype of a, and cannot say that a is a subtype of B. You can only assign a value to its base class object with a subclass object, and you cannot assign a value to its subclass object with a base class object, because the base class object does not contain members of the derived class and cannot assign values to the members of the derived class. Similarly, it is not possible to assign values between different derived class objects of the same base class.

2 A derived class object can override a base class object to assign or initialize a reference to a base class object.

If you have defined a base class A object A1, you can define a reference variable for A1:

  A A1; Define base Class A object A1
  B b1;//define Common derived class B object B1
  a& r=a1;//define reference variable R for base class A object and initialize it with A1


At this point, the reference variable r is the alias of A1, and R and A1 share the same segment of the storage unit. You can also initialize the reference variable R with a subclass object, and change the last line above to

  a& r=b1; Define the reference variable R for the base class A object and initialize it with the derived class B object B1


Or to retain the 3rd line above "a& r=a1;", and to assign a value to r:

  R=B1; B1 The reference Variable r assignment to A1 with the derived Class B object

Note that at this point R is not an alias for B1, nor does it share the same segment of storage with B1. It is just an alias to the base class part of the B1, and R shares the same segment with the base class in B1, and R and B1 have the same starting address.

3 if the parameter of a function is a reference to a base class object or a base class object, the corresponding argument can be in a subclass object.

If there is a function:

  Fun:void Fun (a& R)//parameter is the reference variable of the object of class A
  {
    cout<<r.num<<endl;
  }//Output the reference variable's data member num

The formal parameter of a function is a reference variable of the object of Class A, and the argument should be an object of Class A. Because the subclass object is assignable to the derived class object, the derived class object can automatically convert the type, and you can use the object B1 of the derived class B as the argument when calling the fun function:

   Fun (B1);


Output Class B's Object B1 the value of the base class data member Num.

As before, the value of a base class member in a derived class can only be output in the fun function.

4 The address of a derived class object can be assigned to a pointer variable that points to a base class object, that is, a pointer variable to a base class object can also point to a derived class object.

[Example] defines a base class student (student), and then defines the public derived class graduate (graduate) of the student class, outputting data with pointers to the base class object. This example focuses on pointing to a derived class object with a pointer to a base class object, and in order to reduce the length of the program, only a few members are set in each class. The student class only sets num (school number), name (name) and score (score) 3 data members, graduate class only adds one data member pay (salary). The procedure is as follows:

#include <iostream> #include <string> using namespace std; 
  Class student//declares Student classes {public:student (int, string,float);//Declare constructor void display ();//DECLARE output function Private:int num;
  String name;
Float score;
};
  student::student (int n, string nam,float s)//define constructor {num=n;
  Name=nam;
Score=s;
  } void Student::d isplay ()//define output function {cout<<endl<< "num:" <<num<<endl;
  cout<< "Name:" <<name<<endl;
cout<< "Score:" <<score<<endl;} Class Graduate:public Student//Declaration Common derived class graduate {public:graduate (int, string, float,float);//Declare constructor void display (); Declares the output function private:float pay;
Wages}; Define constructor Graduate::graduate (int n, string nam,float s,float p): Student (n,nam,s), Pay (p) {} void Graduate::d isplay ()// Define output function {Student::d isplay ();//Call display function of Student class cout<< "pay=" <<pay<<endl;} int main () {Studen T STUD1 (1001, "Li", 87.5); Define student class Objects STUD1 graduate Grad1 (2001, "Wang", 98.5,563.5); Define GRAduate class object Grad1 Student *pt=&stud1; Defines a pointer to a student class object and points to stud1 Pt->display (); Call the Stud1.display function pt=&grad1; The pointer points to Grad1 Pt->display ();
 Call Grad1.display Function}

The following analysis of the program is very important, please read and think carefully.

Many readers would argue that there are two display member functions with the same name in the derived class, and the call should be the display function of the derived class graduate object, based on the rules overridden by the same name, called student during the execution of the graduate::d isplay function:: Display function, output num,name,score, and then output the pay value.

In fact, this inference is wrong, first look at the output of the program:

num:1001
name:li
score:87.5

num:2001
name:wang
score:98.5

The first 3 lines are student STUD1 data, the last 3 lines are postgraduate grad1 data, and there is no output pay value.

The problem is that PT is a pointer variable pointing to a Student class object, even if it points to grad1, but actually PT points to the part of Grad1 that inherits from the base class.

By pointing to a pointer to a base class object, you can access only the base class members in the derived class, not the added members of the derived class. So Pt->display () instead of the display function added by the derived class graduate object, but the display function of the base class, output only the num,name,score3 data of the postgraduate Grad1.

If you want to pass the pay of graduate grad1 by pointer output, you can set a pointer variable ptr that points to the derived class object, point it to Grad1, and then call the display function of the derived class object with Ptr->display (). But it's not convenient.

This example shows that pointing a pointer variable to a base class object to a subclass object is legal, secure, and does not present a compilation error. But the application does not fully satisfy people's hopes, and people sometimes want to be able to call the base class and the members of the subclass object by using a base class pointer. If this can be done, the program staff will feel convenient. The following chapters will address this issue. The approach is to use virtual functions and polymorphism.

C + + Virtual base class detailed
Naming conflicts can easily occur when multiple inheritance occurs, even if we are careful to name the member variables and member functions in all classes as different names, and naming conflicts are still possible, such as the very classic diamond inheritance hierarchy. As shown in the following illustration:

Class A derives class B and Class C, Class D inherits from Class B and Class C, and this time the member variables and member functions in Class A inherit into Class D two, one from A-->b-->d this way, and the other from A-->c-->d.

Holds multiple copies of the same name for an indirect base class in a derived class. Although different data can be stored in different member variables, in most cases this is superfluous: because reserving multiple member variables not only takes up more storage space, but also makes naming conflicts easy, and rarely requires it.

To address this problem, C + + provides a virtual base class that retains only one member of the indirect base class in a derived class.

Declaring a virtual base class requires only the virtual keyword in front of the inheritance method, see the following example:

#include <iostream>
using namespace std;
Class a{
protected:
  int A;
Public:
  A (int a): A (a) {}
};
Class B:virtual public a{//Declaration Virtual base class
protected:
  int B;
Public:
  B (int a, int B): A (a), B (b) {}
};
Class C:virtual public a{//Declaration Virtual base class
protected:
  int C;
Public:
  C (int a, int C): A (a), C (c) {}
};
Class D:virtual public B, virtual public c{//declaring virtual base class
private:
  int D;
Public:
  D (int A, int b, int c, int D): A (a), B (A,b), C (A,c), D (d) {}
  void display ();
void D::d isplay () {
  cout<< "a=" <<a<<endl;
  cout<< "b=" <<b<<endl;
  cout<< "c=" <<c<<endl;
  cout<< "d=" <<d<<endl;
}
int main () {
  (new D (1, 2, 3, 4))-> display ();
  return 0;
}

Run Result:

A=1
b=2
c=3
d=4

In this example we use the virtual base class, which has only one copy of the member variable A in the derived class D, so you can access a directly in the display () function without adding the class name and the domain parser.

Note that the constructor of the derived class D differs from the previous usage. In the past, the constructor of a derived class was only responsible for initializing its direct base class, and then its direct base class was responsible for initializing the indirect base class. Now, because the virtual base class has only one member variable in the derived class, initialization of this member variable must be given directly by the derived class. If the virtual base class is not initialized directly by the last derived class, the creation of virtual base classes by direct derived classes such as Class B and Class C for virtual base classes is likely to be contradictory due to different initialization parameters for the virtual base class in Class B and Class C constructors. So it is stipulated that in the final derived class it is not only responsible for initializing its direct base class, but also for initializing the virtual base class.

Some readers will suggest: the constructor of Class D invokes the constructor a of the virtual base class by initializing the table, and the constructors of Class B and Class C also invoke the constructor a of the virtual base class by initializing the table, so that the constructor of the virtual base class is not called 3 times? No need to worry, the C + + compilation system only performs the call of the last derived class on the constructor of the virtual base class, ignoring the invocation of other derived classes of the virtual base class, such as Class B and class C, to the constructor of the virtual base class ensures that the data members of the virtual base class are not initialized more than once.

Finally, note that in order to ensure that a virtual base class inherits only once in a derived class, it should be declared as a virtual base class in all the direct derived classes of the base class, otherwise there will still be multiple inheritance of the base class.

As you can see: Be very careful when using multiple inheritance, there are often two of semantic problems. The above example is simple, if the derivation of more layers, multiple inheritance more complex, the programmer is very easy to trap people mihunzhen, program writing, debugging and maintenance work will become more difficult. As a result, many programmers do not advocate multiple inheritance in a program, and only use multiple inheritance if it is simpler and less than two semantic, or if it is necessary, to solve problems with single inheritance instead of using multiple inheritance. For this reason, many object-oriented programming languages (such as Java, Smalltalk, C #, PHP, and so on) after C + + do not support multiple inheritance.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.