glades
glades

Reputation: 4769

How to get around calling base class constructor from derived class with the same arguments?

I want to use a base object that defines an "interface" and then have derived objects implement it. Every object is initialized with its name which is always the same process: Writing to a member "name_" with parameter passed to the constructor. I want to have derived objects behave exactly the same way as the base object in that regard, so every derived object should write to its name varialbe. However, the problem is that I would need to define an extra constructor in every derived object that writes to the name variable which is cumbersome. The following example does not compile because of this reason. Is there any way around this or is inheritance even the right approach (please feel free to suggest otherwise)?

Non-compiling code (shows what I want to do):

#include <iostream>

class A {
    const std::string name_;
    public:
        A(const std::string name) : name_(name) { std::cout << "creation of object " << name_ << "; this name = " << this->name_ << '\n'; }
};

class B : public A {
    // const std::string name_; -- we do not even need this because "name_" also exists for object B.

    // C++ misses its constructor here :') - I don't
};

int main()
{
    A obj_a{ "A" };

    B obj_b{ "B" };
}

Associated error(s):

source>:20:18: error: no matching function for call to 'B::B(<brace-enclosed initializer list>)'
   20 |     B obj_b{ "B" };
      |                  ^
<source>:12:7: note: candidate: 'B::B(const B&)'
   12 | class B : public A {
      |       ^
<source>:12:7: note:   no known conversion for argument 1 from 'const char [2]' to 'const B&'
<source>:12:7: note: candidate: 'B::B(B&&)'
<source>:12:7: note:   no known conversion for argument 1 from 'const char [2]' to 'B&&'
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:20:18: error: no matching function for call to 'B::B(<brace-enclosed initializer list>)'
   20 |     B obj_b{ "B" };
      |                  ^
<source>:12:7: note: candidate: 'B::B(const B&)'
   12 | class B : public A {
      |       ^
<source>:12:7: note:   no known conversion for argument 1 from 'const char [2]' to 'const B&'
<source>:12:7: note: candidate: 'B::B(B&&)'
<source>:12:7: note:   no known conversion for argument 1 from 'const char [2]' to 'B&&'

Upvotes: 0

Views: 996

Answers (2)

dfrib
dfrib

Reputation: 73186

You may use a using-declaration to

Using-declaration

[...] introduce base class members into derived class definitions.

[...]

Inheriting constructors

If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), all constructors of that base (ignoring member access) are made visible to overload resolution when initializing the derived class.

If overload resolution selects an inherited constructor, it is accessible if it would be accessible when used to construct an object of the corresponding base class: the accessibility of the using-declaration that introduced it is ignored.

as such:

class B : public A {
    using A::A;
};

Note the highlight that the accessibility of the using-declaration itself is ignored, meaning using A::A in the example needn't the be placed under public accessibility - what matters is the accessibility of the inherited constructors in B.

Upvotes: 3

Jarod42
Jarod42

Reputation: 217235

Even add explicitly B constructor

class B : public A
{
public:
    B(const std::string& s) : A(s) {}
};

or "use" the base's ones

class B : public A
{
public:
   using A::A;
};

Upvotes: 0

Related Questions