Initializing base class const member in most derived class - c++

In the below code, I initialize const member of Base class in the most derived class Grandchild.
class Base {
public:
Base(int x_) : x(x_) {}
private:
const int x;
};
class Child : public virtual Base {
public:
virtual ~Child() = 0;
};
class Grandchild : public virtual Child {
public:
Grandchild() : Base(42) {}
};
Child::~Child() {}
int main() {
Grandchild gc;
}
In case of virtual inheritance, the Base class constructor is called by the most derived class. Hence, I expect the code to compile successfully.
clang 4.0 compiles it successfully, whereas gcc 4.9.2 emits the following error:
In constructor 'Grandchild::Grandchild()':
16:27: error: use of deleted function 'Child::Child()'
9:7: note: 'Child::Child()' is implicitly deleted because the default definition would be ill-formed:
9:7: error: no matching function for call to 'Base::Base()'
9:7: note: candidates are: 3:5: note: Base::Base(int)
3:5: note: candidate expects 1 argument, 0 provided
1:7: note: constexpr Base::Base(const Base&)
1:7: note: candidate expects 1 argument, 0 provided
1:7: note: constexpr Base::Base(Base&&)
1:7: note: candidate expects 1 argument, 0 provided
What does the standard say about this?

It seems there was a change in the C++ standard clarifying the requirements of generated constructors for virtual base classes. See CWG257. As far as I understand this text your situation should be allowed. Prior to the change the situation was unclear.
This change was voted into the Working Paper in October 2009, i.e., it should be applicable to compiling with C++11.

Related

C++ - Overriding Virtual Templated Member Functions

In this example:
class MyClass
{
public:
MyClass(int i);
};
template<typename T>
class Base
{
public:
virtual std::unique_ptr<T> createObj()
{
return std::make_unique<T>();
}
};
class Derived : public Base<MyClass>
{
public:
std::unique_ptr<MyClass> createObj() override
{
return std::make_unique<MyClass>(4);
}
};
int main()
{
Derived instance;
auto createdObj = instance.createObj();
}
I cannot call the derived createObj() function. It seems the code is trying to still call the base version with the MyClass instance which leads to compilation failures since the required construction arguments are not passed. Why does this not work as a normal overriden function and call the derived version that does supply the correct arguments?
You misinterpreted the error. The error message is:
In file included from <source>:1:
In file included from /opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/memory:83:
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/bits/unique_ptr.h:962:34: error: no matching constructor for initialization of 'MyClass'
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
^
<source>:15:21: note: in instantiation of function template specialization 'std::make_unique<MyClass>' requested here
return std::make_unique<T>();
^
<source>:19:7: note: in instantiation of member function 'Base<MyClass>::createObj' requested here
class Derived : public Base<MyClass>
^
<source>:6:5: note: candidate constructor not viable: requires single argument 'i', but no arguments were provided
MyClass(int i);
^
<source>:3:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
class MyClass
^
<source>:3:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
1 error generated.
Base<MyClass> tries to default construct a MyClass but MyClass has no default constuctor. Even if you are not trying to call Base<MyClass>::createObj the method must be valid because it is instantiated as part of Base<MyClass>.
In other words, merely instantiating Base<MyClass> will fail. Not calling the method does not make it less of an error.
I am not entirely sure whats the aim, but if you make the method pure virtual in Base your code compiles without issues:
#include <memory>
class MyClass
{
public:
MyClass(int i) {}
};
template<typename T>
class Base
{
public:
virtual std::unique_ptr<T> createObj() = 0;
};
class Derived : public Base<MyClass>
{
public:
std::unique_ptr<MyClass> createObj() override
{
return std::make_unique<MyClass>(4);
}
};
int main()
{
Derived instance;
auto createdObj = instance.createObj();
}
Alternatively you could provide a default contructor for MyClass.

Class derived from a class with multiple inheritance in C++: the derived class is trying to call the root base class constructor

I'm sorry if this feels like a cheap sequel to my last question.
I have a diamond inheritance where D is derived from both B and C, who in turn are both derived (virtually) from A. A, B and C are abstract, and thanks to the answers to my previous questions the compiler is now aware of it and all is fine.
Now, I need to create a class E derived from D. As far as I know, normally the constructor E::E should call D::D, and it would be D::D's job to call all of A::A, B::B, and C::C.
But my compiler really insists on having E::E call A::A itself.
Here is a simple example I made:
class A { //abstract
protected:
A(int foo) {}
virtual void f() =0;
};
class B: public virtual A { // abstract
protected:
B() {}
};
class C: public virtual A { // abstract
protected:
C() {}
};
class D: public B, public C { // concrete
public:
D(int foo, int bar) :A(foo) {}
void f() {}
};
class E: public D { // concrete
public:
E(int foo, int bar, int buz) :D(foo, bar) {}
};
int main()
{
return 0;
}
And here is the compilation error:
$ g++ test.cpp
test.cpp: In constructor ‘E::E(int, int, int)’:
test.cpp:25:49: error: no matching function for call to ‘A::A()’
25 | E(int foo, int bar, int buz) :D(foo, bar) {}
| ^
test.cpp:3:9: note: candidate: ‘A::A(int)’
3 | A(int foo) {}
| ^
test.cpp:3:9: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(const A&)’
1 | class A { //abstract
| ^
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(A&&)’
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
I know the virtual inheritance is correct and I know the compiler knows which classes I intend to be abstract and which I intend to be instantiable, because if I remove class E, the code compiles.
What am I missing?
But my compiler really insists on having E::E call A::A itself.
Like I explained in anwer to your previous question: "the constructor of the most derived class calls the constructor of the virtual base".
All non-abstract classes in a hierarchy that contains virtual bases must correctly initialise the virtual bases because they can potentially be instantiated as the most derived class. For example, if you create an instance of E, then it is the constructor of E that initialises the virtual base A.
In your code, the constructor of E attempts to use the default constructor of A by omitting the initialiser. But A is not default constructible, so the program is ill-formed.
What am I missing?
The initialiser for the virtual base A in the constructor of E.
As far as I know, there is no way to delegate the construction to of the virtual base to another concrete base such as D.

Why do the constructor of the derived classes want to initialize the virtual base class in C++?

My understanding, for instance reading this, is that the constructor of a derived class does not call its virtual base class' constructor.
Here is a simple example I made:
class A {
protected:
A(int foo) {}
};
class B: public virtual A {
protected:
B() {}
};
class C: public virtual A {
protected:
C() {}
};
class D: public B, public C {
public:
D(int foo, int bar) :A(foo) {}
};
int main()
{
return 0;
}
For some reason, the constructors B::B() and C::C() are trying to initialize A (which, again in my understanding, should have already been initialized by D at this point):
$ g++ --version
g++ (GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ test.cpp
test.cpp: In constructor ‘B::B()’:
test.cpp:8:13: error: no matching function for call to ‘A::A()’
8 | B() {}
| ^
test.cpp:3:9: note: candidate: ‘A::A(int)’
3 | A(int foo) {}
| ^
test.cpp:3:9: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(const A&)’
1 | class A {
| ^
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(A&&)’
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
test.cpp: In constructor ‘C::C()’:
test.cpp:13:13: error: no matching function for call to ‘A::A()’
13 | C() {}
| ^
test.cpp:3:9: note: candidate: ‘A::A(int)’
3 | A(int foo) {}
| ^
test.cpp:3:9: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(const A&)’
1 | class A {
| ^
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(A&&)’
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
I'm certain there is something very basic I misunderstood or am doing wrong, but I can't figure what.
The constructor of virtual base is constructed. It is constructed conditionally. That is, the constructor of the most derived class calls the constructor of the virtual base. If - this is the condition - the derived class with virtual base is not the concrete class of the constructed object, then it will not construct the virtual base because it has already been constructed by the concrete class. But otherwise it will construct the virtual base.
So, you must correctly initialise the virtual base class in constructors of all derived classes. You simply must know that specific initialisation doesn't necessarily happen in case the concrete class is not the one which you are writing. The compiler doesn't and cannot know whether you will ever create direct instances of those intermediate classes, so it cannot simply ignore their broken constructors.
If you made those intermediate classes abstract, then the compiler would know that they are never the most concrete type and thus their constructor would not be required to initialise the virtual base.
For some reason, the constructors B::B() and C::C() are trying to initialize A (which, again in my understanding, should have already been initialized by D at this point):
But what should compiler do if somebody constructs C solo? The final object D will call the constructor of A but you define constructor to C which implies that it can be constructed but the constructor is faulty cause it cannot construct A.
Putting aside more complex class hierarchies, for any derived type there is exactly one copy of its virtual base. The rule is that the constructor for the most-derived type constructs that base. The compiler has to generate code to handle the bookkeeping for that:
struct B { };
struct I1 : virtual B { };
struct I2 : virtual B { };
struct D : I1, I2 { };
B b; // `B` constructor initializes `B`
I1 i1; // `I1` constructor initializes `B` subobject
I2 i2; // `I2` constructor initializes `B` subobject
So far, it's easy enough to picture, since the initialization is done the same way as it would be if B was not a virtual base.
But then you do this:
D d; // which constructor initializes `B` subobject?
If the base wasn't virtual, the I1 constructor would initialize its B subject, and the I2 constructor would initialize its B subobject. But because it's virtual, there's only one B object. So which constructor should initialize it? The language says that the D constructor is responsible for that.
And the next complication:
struct D1 : D { };
D1 d1; // `D1` constructor initializes `B` subobject
So, along the way we've created five different objects, each with a virtual base of type B, and each with the B subobject being constructed from a different constructor.
Putting the responsibility on the most-derived type makes the initialization easy to understand and to visualize. There could have been other rules, but this one really is the simplest.

Inheritance, Copy Constructors and Implicit Typecasting

I have a derived class which I want to be able to construct using the copy constructor where the argument is an instance of the base class.
I am sure this should be possible in C++. Here is an example:
#include <string>
class Base
{
public:
friend
void swap(Base& l, Base& r)
{
using std::swap;
swap(l.a, r.a);
}
Base()
: a{1}
{
}
Base(const int a)
: a{a}
{
}
virtual
~Base()
{
}
Base(const Base& base)
: a{base.a}
{
}
Base(Base&& base)
: Base()
{
swap(*this, base);
}
Base& operator=(Base base)
{
swap(*this, base);
return *this;
}
protected:
int a;
};
class Derived : public Base
{
protected:
std::string b;
};
int main()
{
Base base(2);
Derived derived(base);
}
The error (g++ main.cpp) is:
main.cpp: In function ‘int main()’:
main.cpp:71:31: error: no matching function for call to ‘Derived::Derived(Base&)’
class Derived derived(base);
^
main.cpp:57:7: note: candidate: Derived::Derived()
class Derived : public Base
^~~~~~~
main.cpp:57:7: note: candidate expects 0 arguments, 1 provided
main.cpp:57:7: note: candidate: Derived::Derived(const Derived&)
main.cpp:57:7: note: no known conversion for argument 1 from ‘Base’ to ‘const Derived&’
main.cpp:57:7: note: candidate: Derived::Derived(Derived&&)
main.cpp:57:7: note: no known conversion for argument 1 from ‘Base’ to ‘Derived&&’
So the compiler doesn't know how to convert from an instance of Base to Derived implicitly.
I thought that this should be legal in C++. Do I require an explicit conversion statement?
What are you doing doesn't make much sense by itself because Base is not a sub-type of Derived so it can't be used as its replacement/substitution, however you could attempt to give it sense (same as with initialization from any other type) by writing a converting constructor:
class Derived : public Base
{
public:
Derived(const Base &bs) : Base(bs), b("constructed from base") {}
protected:
std::string b;
};
This would first initialize Derived Base part from bs and then init the string b with some value (though you can leave it out if you want it to be default-inited to empty string).
https://godbolt.org/z/GMELW_
Yes, you need to cast explicitely from Base to Derived. Every Mercedes is a car, but not every car is a Mercedes.
this statement Derived derived(base); or to simplify B b(A()); do an implicit conversion of type A to type B, which is legal only if class B inherit directly or indirectly from Class A.
Why ? Because class B could contains new information, in your case a string b, and a cast don't "append" information.
There is a simple way of solving this problem: By pulling the Base constructor into the scope of Derived.
This can be done with the using statement:
class Derived : public Base
{
public:
using Base::Base; // Pulls in the Base class constructors into the scope of Derived
...
};
I found what I was looking for (I couldn't remember the name so couldn't google it before). However this technique actually doesn't work due to the fact that I am using inheritance. (Or at least I don't know how to make it work.)
Type conversion operator:
Base::operator Derived()
{
Derived derived;
derived.a = a;
return derived;
}
This doesn't actually compile because the compiler doesn't know what Derived is. (Since Derived inherits from Base.) I don't know if it is possible to make this work by separating the compilation units.

Do all derived classes from a hierarchy require access to the virtual base class?

When I try to compile the following code:
class A {
public:
A(int v) : virt(v) { }
int virt;
int getVirt(void) const { return virt; }
};
class B : private virtual A {
protected:
B(int v) : A(v) { }
using A::getVirt;
};
class C : public B, private virtual A {
protected:
C(int v) : A(v), B(v) { }
using A::getVirt;
};
class D : public C {
public:
D(void) : C(3) { }
using C::getVirt;
};
#include <iostream>
int main(int argc, char *argv[]) {
D d;
std::cout << "The number is: " << d.getVirt() << std::endl;
return 0;
}
I get an error about D not instantiating A; is that correct? If a virtual base is embedded in the hierarchy do all derived classes also need to derive from that base, virtually, so they can call the parametric constructor of the virtual base?
BTW, here are the errors produced by G++:
Main.cpp: In constructor ‘D::D()’:
Main.cpp:22:18: error: no matching function for call to ‘A::A()’
Main.cpp:22:18: note: candidates are:
Main.cpp:3:5: note: A::A(int)
Main.cpp:3:5: note: candidate expects 1 argument, 0 provided
Main.cpp:1:7: note: A::A(const A&)
Main.cpp:1:7: note: candidate expects 1 argument, 0 provided
That has nothing to do with access control (at least not primarily). Rather, you have to understand how virtual bases work: The virtual base subobject is initialized by the most derived class. Since you don't mention A in the constructor initializer list of D, the default constructor is tried, but doesn't exist.
To fix this, initalize A properly in D:
D() : A(3), C(3) { }
When you say A(3), name lookup is performed according to 12.6.2/2:
In a mem-initializer-id an initial unqualified identifier is looked up in the scope of the constructor’s class and, if not found in that scope, it is looked up in the scope containing the constructor’s definition.
As Drew Dorman rightly points out, you can force a direct path to the virtual base class by calling it ::A and thus obtaining the desired access.
As Kerrek SB mentions, you need to initialize A in the constructor for D.
However, you must also explicitly tell the compiler that you are not accessing A from its (privately) derived context by using the scope operator.
class D : public C {
public:
D(void) : ::A(3), C(3) { }
// ^^ Access this constructor from a global context
using C::getVirt;
};
This also means that your constructor must be public, as is already the case with your code.