I am trying to compile a code that involves inheritance.
#include "MapEntityClass.h"
class RectangularEntityClass:public MapEntityClass
{
public:
void drawOnMap(MapClass *mapObj) const;
protected:
};
The parent class is MapEntityClass, which does not have a default constructor, but has a value constructor. When I compile, I get the following error:
RectangularEntityClass.h: In constructor ‘RectangularEntityClass::RectangularEntityClass()’:
RectangularEntityClass.h:12:7: error: no matching function for call to ‘MapEntityClass::MapEntityClass()’
class RectangularEntityClass:public MapEntityClass
^
RectangularEntityClass.h:12:7: note: candidates are:
In file included from main.cpp:1:0:
MapEntityClass.h:32:5: note: MapEntityClass::MapEntityClass(const PixelLocationClass&, const ColorClass&)
MapEntityClass(
^
MapEntityClass.h:32:5: note: candidate expects 2 arguments, 0 provided
Any idea what is wrong?
In inheritance, the subclass need not have a constructor only if parent class doesn't have a constructor or only default constructor.
In any case, if parent class happens to have a parameterized constructor, the subclass should have a parameterized constructor which should invoke the parent class constructor.
Example:
class A {
int aVal;
public:
A(int);
};
A::A(int aVal)
{
this->aVal = aVal;
}
class B : public A {
int bVal;
public:
B(int, int)
};
B::B(int aVal, int bVal) : A(aVal)
{
this->bVal = bVal;
}
Related
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.
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.
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.
I'm trying to define some classes but I get some errors I'm not being able to decode.
I do not understand why it states I'm using Test's constructor when I am not.
test.cpp: In constructor 'Test2::Test2(int)':
test.cpp:12:34: error: use of deleted function 'Test::Test()'
explicit Test2(const int line) {}
^
test.cpp:3:7: note: 'Test::Test()' is implicitly deleted because the default definition would be ill-formed:
class Test : public std::runtime_error {
^
test.cpp:3:7: error: no matching function for call to 'std::runtime_error::runtime_error()'
test.cpp:3:7: note: candidates are:
In file included from test.cpp:1:0:
C:/Development/MinGW/x86_64-w64-mingw32/include/c++/stdexcept:119:5: note: std::runtime_error::runtime_error(const string&)
runtime_error(const string& __arg);
^
C:/Development/MinGW/x86_64-w64-mingw32/include/c++/stdexcept:119:5: note: candidate expects 1 argument, 0 provided
C:/Development/MinGW/x86_64-w64-mingw32/include/c++/stdexcept:112:9: note: std::runtime_error::runtime_error(const std::runtime_error&)
class runtime_error : public exception
^
C:/Development/MinGW/x86_64-w64-mingw32/include/c++/stdexcept:112:9: note: candidate expects 1 argument, 0 provided
Minimal working example (gcc 4.9.1, g++ -std=c++11):
#include <stdexcept>
class Test : public std::runtime_error {
public:
virtual ~Test() noexcept {}
virtual const char * what() const noexcept = 0;
};
class Test2 : public Test {
public:
explicit Test2(const int line) {}
virtual const char * what() const noexcept { return ""; }
};
Your constructor in the class Test2 does not pass any arguments to the base class. So the default constructor of the base class - which is Test - is used. And the same story with Test then - its default constructor tries to call the default constructor of its base class - std::runtime_error - which does not exist. Hence the error. You need to pass message string argument to std::runtime_error, e.g.:
Test() : std::runtime_error("some message") {}
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.