简体   繁体   中英

Inherited Constructors in C++

I'm trying to practice Inheriting Constructors in C++. I have compiled and run following program in gcc and it's working fine.

#include<iostream>
using namespace std;

class Base1
{
public:
        Base1()
        {
                cout<<"Base1 Default Constructor\n";
        }
        Base1(int i)
        {
                cout<<"Base1 parametrized Constructor\n";
        }
};

class Base2
{
public:
        Base2()
        {
                cout<<"Base2 Default Constructor\n";
        }
        Base2(const string& s)
        {
                cout<<"Base2 parametrized Constructor\n";
        }
};

class Derived :public Base1, public Base2
{
public:
        using Base1::Base1;
        using Base2::Base2;
};

int main()
{
        Derived d1(3);        // OK 
        Derived d2("hello");  // OK 
}

Output:

Base1 parametrized Constructor
Base2 Default Constructor
Base1 Default Constructor
Base2 parametrized Constructor

But, I'm wondering, Why is the default constructor called?

The default constructors are being called because Derived inherits from Base1 and Base2 . Both of those bases need to be constructed when you construct a Derived object. So when you do

Derived d1(3);

You call Base1(int i) . Now you need to construct the Base2 part and since you do not specify how, the compiler default constructs it. The same thing happens in

Derived d2("hello");

Since you do not specify how to construct the Base1 part in the constructor the compiler default constructs it for you. Then Base2(const string& s) is called to construct the Base2 part.

Essentially what you have is

class Derived :public Base1, public Base2
{
public:
        Derived(int n) : Base1(n), Base2() {}
        Derived(const std::string& str) : Base1(), Base2(str) {}
};

From cppreference http://en.cppreference.com/w/cpp/language/using_declaration
If the using-declaration refers to a constructor of a direct base of the class being defined (eg using Base::Base;), constructors of that base class are inherited, according to the following rules:

1) A set of candidate inheriting constructors is composed of
a) All non-template constructors of the base class (after omitting ellipsis parameters, if any) (since C++14)
b) For each constructor with default arguments or the ellipsis parameter, all constructor signatures that are formed by dropping the ellipsis and omitting default arguments from the ends of argument lists one by one
c) All constructor templates of the base class (after omitting ellipsis parameters, if any) (since C++14)
d) For each constructor template with default arguments or the ellipsis, all constructor signatures that are formed by dropping the ellipsis and omitting default arguments from the ends of argument lists one by one
2) All candidate inherited constructors that aren't the default constructor or the copy/move constructor and whose signatures do not match user-defined constructors in the derived class, are implicitly declared in the derived class. The default parameters are not inherited:

struct B1 {
    B1(int);
};
struct D1 : B1 {
    using B1::B1;
// The set of candidate inherited constructors is 
// 1. B1(const B1&)
// 2. B1(B1&&)
// 3. B1(int)

// D1 has the following constructors:
// 1. D1()
// 2. D1(const D1&) 
// 3. D1(D1&&)
// 4. D1(int) <- inherited
};

struct B2 {
    B2(int = 13, int = 42);
};
struct D2 : B2 {
    using B2::B2;
// The set of candidate inherited constructors is
// 1. B2(const B2&)
// 2. B2(B2&&)
// 3. B2(int = 13, int = 42)
// 4. B2(int = 13)
// 5. B2()

// D2 has the following constructors:
// 1. D2()
// 2. D2(const D2&)
// 3. D2(D2&&)
// 4. D2(int, int) <- inherited
// 5. D2(int) <- inherited
};

The inherited constructors are equivalent to user-defined constructors with an empty body and with a member initializer list consisting of a single nested-name-specifier, which forwards all of its arguments to the base class constructor.

It has the same access as the corresponding base constructor. It is constexpr if the user-defined constructor would have satisfied constexpr constructor requirements. It is deleted if the corresponding base constructor is deleted or if a defaulted default constructor would be deleted (except that the construction of the base whose constructor is being inherited doesn't count). An inheriting constructor cannot be explicitly instantiated or explicitly specialized.

If two using-declarations inherit the constructor with the same signature (from two direct base classes), the program is ill-formed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM