Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor inheritance and custom constructors

Using this hierarchy :

struct TestBase {
    // Constructor
    TestBase();
    TestBase(int a);
    TestBase(TestBase const &testBase);

    // Destructor
    virtual ~TestBase();
};

struct TestChild : public TestBase {
    // Constructor inheritance
    using TestBase::TestBase;
};

With this test code :

TestBase testBase;                  // 1) Custom constructor
TestChild testChild;                // 2) Default constructor created by the compiler
TestChild testChild2(1);            // 3) Inherited from parent with 'using' keyword
TestChild testChild3(testChild);    // 4) Default copy constructor created by the compiler ?
TestChild testChild4(testBase);     // 5) Doesn't work, why it doesn't inherit ?

First I was thinking that in test 4 the copy constructor was inherited from TestBase (by the 'using' keyword) but in fact it's because the compiler generates a default copy constructor which calls copy constructor of the parent class, is it correct ?

A copy constructor can't be inherited because it must have the same parameter type than the class, is it correct too ?

But why test 5 doesn't compile ? It's not a copy constructor for the TestChild class so it must be inherited, no?


This is the error message:

foo.cpp: In function ‘int main()’:
foo.cpp:21:34: error: no matching function for call to ‘TestChild::TestChild(TestBase&)’
 TestChild testChild4(testBase);     // 5) Doesn't work, why it doesn't inherit ?
                              ^
foo.cpp:21:34: note: candidates are:
foo.cpp:11:12: note: TestChild::TestChild()
     struct TestChild : public TestBase {
            ^
foo.cpp:11:12: note:   candidate expects 0 arguments, 1 provided
foo.cpp:13:25: note: TestChild::TestChild(int)
         using TestBase::TestBase;
                         ^
foo.cpp:13:25: note:   no known conversion for argument 1 from ‘TestBase’ to ‘int’
foo.cpp:11:12: note: TestChild::TestChild(const TestChild&)
     struct TestChild : public TestBase {
            ^
foo.cpp:11:12: note:   no known conversion for argument 1 from ‘TestBase’ to ‘const TestChild&’
foo.cpp:11:12: note: TestChild::TestChild(TestChild&&)
foo.cpp:11:12: note:   no known conversion for argument 1 from ‘TestBase’ to ‘TestChild&&’
like image 752
Johnmph Avatar asked Sep 03 '25 06:09

Johnmph


1 Answers

A using-declaration that names a constructor implicitly declares a set of inherited constructors, but what is worth noting is that there are certain constructs which are not inherited.


What does the standard say?

12.9 Inheriting Constructors [class.inhctor]

3 For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy ,or move constructor for that class.

The above sentence might look more cryptic that it actually is.. what it is saying, in simple english, is that a constructor is only inherited in the context of using Base::Base if the constructor;

  • isn't a template, and;
  • isn't a default constructor (ie. having no parameters), and;
  • isn't a copy/move constructor, and;
  • there's no explicit declaration in Derived that matches a constructor normally inherited from Base

Conclusion

With the above in mind we realize that the constructor in TestBase that takes a TestBase const& is a copy-constructor, and since copy-constructors are not inherited, that's the reason for it being non-present in TestChild.

like image 109
Filip Roséen - refp Avatar answered Sep 04 '25 19:09

Filip Roséen - refp