1. Problem Description

In the inheritance system, if a derived class wants to use the base class constructor, it needs to explicitly declare it in the constructor.

As follows:

struct A { A(int i){} }; struct B:A { B(int i):A(i){} };

Here, B is derived from A, and B

also calls A's constructor in its constructor, thereby completing the passing of the constructor.

Another example is as follows. When B contains member variables:

struct A { A(int i){} }; struct B:A { B(int i):A(i),d(i){} int d; };

Now the struct B derived from A includes a member variable. We initialize member d at the same time as initializing the base class A. The problem now is: if the base class has numerous constructors with different versions, then in the derived class, following the above approach, we still have to write many corresponding "pass-through" constructors. For example:

struct A { A(int i) {} A(double d,int i){} A(float f,int i,const char* c){} //...and so on, a series of constructor versions }; struct B:A { B(int i):A(i){} B(double d,int i):A(d,i){} B(folat f,int i,const char* c):A(f,i,e){} //......and so on, many constructors corresponding to the base class constructors };

Obviously, when the base class has many constructors, the derived class constructor writing becomes very cumbersome and quite inconvenient.

2. Solution to the Problem

We can simplify this problem through a using declaration. Let's look at an example.

struct Base { void f(double i){ cout<<"Base:"<<i<<endl; } }; struct Drived:Base { using Base::f; void f(int i){ cout<<"Drived:"<<i<<endl; } };

In the code, both the base class and the derived class declare a function f with the same name. But the method in the derived class is different from the base class version. Here, a using declaration is used to indicate that the derived class also uses the base class version of function f. In this way, the derived class has two versions of the f function. What needs to be explained here is: if a using declaration is not used to inherit the parent class's same-named function, then the f function defined in the derived class will hide the parent class's f function. Of course, if the derived class does not define this same-named f function at all, it will still choose to use the base class's f function.

We can apply this method to constructor inheritance as well. That is, the derived class can use a using statement to declare that it will inherit all the base class constructors in the subclass. For example:

struct A { A(int i) {} A(double d,int i){} A(float f,int i,const char* c){} //...and so on, a series of constructor versions }; struct B:A { using A::A; //One sentence handles the inheritance of all the base class constructors //...... };

Now, through the using A::A declaration, all constructors in the base class are inherited into the derived class. What's even more clever is that this is implicitly declared inheritance. That is, if an inherited constructor is not used by relevant code, the compiler will not generate actual function code for it, which saves more target code space than pass-through forwarding of the various base class constructors. But there is another problem at this point:

When using the using statement to inherit base class constructors, the derived class cannot initialize new class members defined by the class itself. We can use class member initializer expressions to set default initial values for derived class members. For example:

struct A { A(int i) {} A(double d,int i){} A(float f,int i,const char* c){} //...and so on, a series of constructor versions }; struct B:A { using A::A; int d{0}; };

Note:

1. For inherited constructors, the default values of parameters are not inherited. Moreover, default values will cause the base class to generate multiple constructor versions (that is, parameters are removed from the back to the front until the no-argument constructor is included; of course, if it is a default copy constructor, it is also included). All these constructor versions will be inherited by the derived class.

2. Conflict handling in inherited constructors: When a derived class has multiple base classes, some constructors among the multiple base classes may cause the function names of the inherited constructors in the derived class to be the same.

If the parameters are also the same, then the inherited constructors in the derived class will lead to illegal derived class code. For example:

struct A { A(int){} }; struct B { B(int){} }; struct C:A,B { using A::A; using B::B; };

Here, the inherited constructors in the derived class will conflict. One solution is to explicitly inherit the conflicting constructors of the class, preventing the implicit generation of the corresponding inherited constructors to avoid conflicts.

struct C:A,B { using A::A; using B::B; C(int){} };

3. If the base class constructor is declared as a private constructor, or the derived class virtually inherits from the base class, then inherited constructors cannot be declared in the derived class.

4. If inherited constructors are used, the compiler will not generate a default constructor for the derived class. Therefore, we need to pay attention to whether the no-argument version of the inherited constructor is necessary.

Source: http://www.cnblogs.com/yangykaifa/p/6737354.html