Separating classes in header and source causes build errors - c++

The following code snippets are intentionally made simple only to illustrate the problem. There are two cases I want to show here. The first one in which all code is put in a single file as follows.
#include <iostream>
class Base
{
protected:
double data;
public:
Base(double data);
};
Base::Base(double data = 10) : data{data}{}
class Derived : public Base
{
};
int main()
{
Derived d;
std::cout<<"End of program";
return 0;
}
So far so good. Everything works as expected.
However, if I split the classes into their headers and sources as follows.
Base.hpp
// Base.hpp
#pragma once
class Base
{
protected:
double data;
public:
Base(double data);
};
Base.cpp
// Base.cpp
#include "Base.hpp"
Base::Base(double data = 10) : data{data} {}
Derived.hpp
// Derived.hpp
#pragma once
#include "Base.hpp"
class Derived : public Base
{
};
Derived.cpp
// Derived.cpp
#include "Derived.hpp"
separate.cpp
// separate.cpp
#include "Derived.hpp"
#include <iostream>
int main(){
Derived d;
std::cout<<"End of program";
return 0;
}
I got a lot of build errors as follows.
> Executing task: C/C++: g++.exe build active file <
Starting build...
"C:\mingw32\bin\g++.exe" -g *.cpp -o separate.exe -I F:\StackExchange\Programming\VSCode-Template/cpp
separate.cpp: In function 'int main()':
separate.cpp:5:13: error: use of deleted function 'Derived::Derived()'
Derived d;
^
In file included from separate.cpp:1:
Derived.hpp:4:7: note: 'Derived::Derived()' is implicitly deleted because the default definition would be ill-formed:
class Derived : public Base
^~~~~~~
Derived.hpp:4:7: error: no matching function for call to 'Base::Base()'
In file included from Derived.hpp:2,
from separate.cpp:1:
Base.hpp:8:5: note: candidate: 'Base::Base(double)'
Base(double data);
^~~~
Base.hpp:8:5: note: candidate expects 1 argument, 0 provided
Base.hpp:2:7: note: candidate: 'constexpr Base::Base(const Base&)'
class Base
^~~~
Base.hpp:2:7: note: candidate expects 1 argument, 0 provided
Base.hpp:2:7: note: candidate: 'constexpr Base::Base(Base&&)'
Base.hpp:2:7: note: candidate expects 1 argument, 0 provided
Build finished with error(s).
The terminal process terminated with exit code: -1.
Questions
Could you tell me why this issue happened and how to fix it?

The default argument belongs in the declaration (in the header), not in the definition (in the .cpp file).

Could you tell me why this issue happened
It is because you removed the default argument from the declaration of the constructor. It is no longer a default constructor. The default argument in the definition is only visible in the translation unit containing the definition.
how to fix it?
Move the default arguments of the constructor back to the declaration.

Related

C++ Creating variables from protected abstract/derived class

I am trying to figure out where I am going wrong with creating variables from a derived class. I have the abstract class, the derived class and am trying to create the derived class as a variable in the main testing program. However I get the error: no matching function for call to DerivedPlayer::DerivedPlayer()’. I haven't been able to find the correct syntax as to create and initialize a variable of the derived class. Also note that the abstract class's constructor is protected.
Abstract Header (Base.h)
#ifndef BASE_H_
#define BASE_H_
#include <iostream>
#include <vector>
class Base {
public:
virtual ~Base() {}
protected:
Base(std::string s) : x(0), s(s), v(0) {}
int x;
std::string s;
std::vector<int> v;
};
#endif
Derived Header (Derived.h)
#ifndef DERIVED_H_
#define DERIVED_H_
#include "Base.h"
class Derived : public Base {
public:
Derived(std::string name){ s = name; }
virtual ~Derived();
};
#endif
Test Code (InTest.cpp)
#include <iostream>
#include "Derived.h"
int main() {
Derived a = Derived("R2-D2");
Derived b = Derived("C-3PO");
return 0;
}
Build Log
03:23:52 **** Incremental Build of configuration Debug for project InTest ****
make all
Building file: ../src/InTest.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/InTest.d" -MT"src/InTest.o" -o "src/InTest.o" "../src/InTest.cpp"
In file included from ../src/InTest.cpp:2:0:
../src/Derived.h: In constructor ‘Derived::Derived(std::string)’:
../src/Derived.h:8:27: error: no matching function for call to ‘Base::Base()’
Derived(std::string name){ s = name; }
^
../src/Derived.h:8:27: note: candidates are:
In file included from ../src/Derived.h:4:0,
from ../src/InTest.cpp:2:
../src/Base.h:12:2: note: Base::Base(std::string)
Base(std::string s) : x(0), s(s), v(0) {}
^
../src/Base.h:12:2: note: candidate expects 1 argument, 0 provided
../src/Base.h:7:7: note: Base::Base(const Base&)
class Base {
^
../src/Base.h:7:7: note: candidate expects 1 argument, 0 provided
make: *** [src/InTest.o] Error 1
03:23:52 Build Finished (took 214ms)
Here's the main part of the error message:
../src/Derived.h: In constructor ‘Derived::Derived(std::string)’:
../src/Derived.h:8:27: error: no matching function for call to ‘Base::Base()’
Derived(std::string name){ s = name; }
Because Derived inherits from Base, each time a Derived object is constructed the Base class constructor also have to run. The problem with your current code is that you let the default Base constructor be called, but there isn't any.
You solve it by "calling" the correct Base constructor in the Derived constructor initializer list:
Derived::Derived(std::string name)
: Base(name)
{}

std::set with derived class object but base class comparator with gcc8.1

a.h
#ifndef _A__
#define _A__
class A {
public:
struct Less {
bool operator() (const A* const &k1, const A* const &k2) const
{
return k1->_a < k2->_a;
}
};
A(int a) : _a(a)
{
;
}
virtual ~A()
{
;
}
private:
int _a;
};
#endif
b.h
#ifndef _B__
#define _B__
#include "a.h"
class B : public A {
public:
B(int a) : A(a)
{
;
}
~B()
{
;
}
};
#endif // _B__
c.cpp
#include <set>
#include "a.h"
class B;
class C
{
std::set<B*, A::Less> _set;
};
When c.cpp is compile with g++ 8.1, it fails to compile with this static check error
/export/dev6/rajpal/gcc/8.1.0/bin/g++ -c c.cpp
In file included from /export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/set:60,
from c.cpp:1:
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_tree.h: In instantiation of 'class std::_Rb_tree<B*, B*, std::_Identity<B*>, A::Less, std::allocator<B*> >':
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_set.h:133:17: required from 'class std::set<B*, A::Less>'
c.cpp:6:25: required from here
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_tree.h:452:21: error: static assertion failed: comparison object must be invocable with two arguments of key type
static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I understand error is because at compile time, compiler is not able to determine how to compare _Key=B* and if I make available definition of B, it should work just fine.
But, my question is if there is any way to tell compiler that B is actually derived from A and there is a way to compare A objects.
Also please note that I don't want to change std::set<B*, A::Less> to std::set<A*, A::Less> which should also fix this problem.
Well, this is actually a libstdc++ bug, and will be fixed in GCC 8.4:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85965
But, my question is if there is any way to tell compiler that B is actually derived from A
The only way to do that is to make the definition of B visible where you need that information.
There is nothing like forward declaration of classes to indicate that B is derived from A.

GCC expected template-name before ‘<’ token error [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I´ve browsed other similar topics and did not find an answer to my problem...
The code below illustrates the situation. A Base class and a Derived class:
Base.hpp
namespace test {
template<class T>
class Base {
public:
Base();
virtual ~Base();
};
}
Base.cpp
#include "Base.hpp"
namespace test {
template<class T>
Base<T>::Base() {
// TODO Auto-generated constructor stub
};
template<class T>
Base<T>::~Base() {
// TODO Auto-generated destructor stub
};
}
Derived.hpp
namespace test {
class Derived : public Base<int> {
public:
Derived();
virtual ~Derived();
};
} /* namespace aeirtuaccess */
Derived.cpp
#include "Derived.hpp"
namespace test {
Derived::Derived() {
// TODO Auto-generated constructor stub
};
Derived::~Derived() {
// TODO Auto-generated destructor stub
};
}
When I compile this code with Coliru - see it in action here, it works fine, but when I go to my Ubuntu environment using g++ I´m having the following error:
>g++ Base.cpp Derived.cppIn file included from Derived.cpp:2:0:
Derived.hpp:3:28: error: expected template-name before ‘<’ token
class Derived : public Base<int> {
^
Derived.hpp:3:28: error: expected ‘{’ before ‘<’ token
Derived.hpp:3:28: error: expected unqualified-id before ‘<’ token
Derived.cpp:6:18: error: invalid use of incomplete type ‘class test::Derived’
Derived::Derived() {
^
In file included from Derived.cpp:2:0:
Derived.hpp:3:7: error: forward declaration of ‘class test::Derived’
class Derived : public Base<int> {
^
Derived.cpp:11:19: error: invalid use of incomplete type ‘class test::Derived’
Derived::~Derived() {
^
In file included from Derived.cpp:2:0:
Derived.hpp:3:7: error: forward declaration of ‘class test::Derived’
class Derived : public Base<int> {
Is there any difference between the compilers ? Should I use a specific g++ flag or version ? Is there something else that I need to do to fix that in my Ubuntu environment ?
In Derived.hpp, you need to add:
#include "Base.hpp"
at the top. Otherwise, the compiler doesn't know what Base refers to when compiling this file.

Invoke a base class constructor from the other module

Let I've two .cpp files: a.cpp and b.cpp which contains classes defenition as the following:
//a.cpp
class A
{
public:
A(){ \\some actions }
}
//b.cpp
class A;
class B : A
{
public:
B():A(){ \\some actions }
}
But during the compile time I've an error. The error's description is:
ConcreteSubject.cpp:5:25: error: invalid use of incomplete type ‘class
Subject’ ConcreteSubject.cpp:3:7: error: forward declaration of ‘class
Subject’ ConcreteSubject.cpp: In constructor
‘ConcreteSubject::ConcreteSubject()’: ConcreteSubject.cpp:21:38:
error: type ‘Subject’ is not a direct base of ‘ConcreteSubject’
Is it possible to avoid #include "a.cpp"?
You should move class declaration of A to a header file and include that header file in you b.cpp file. If you don't do this, b.cpp compilation unit has no way to know the list of constructors implemented (explicitly or implicitly) by classs A.
Including a cpp file is not a good idea. You should not do this.
//a.h
class A
{
public:
A();
}
//a.cpp
A::A(){ \\some actions }
//b.cpp
#include "a.h"
class B : A
{
public:
B():A(){ \\some actions }
}

Invalid application of 'sizeof' to incomplete type ( created classes)

I have next classes:
State.hpp
...
class Engine;
namespace window
{
class State
{ ... } }
WConsole.hpp
...
class Engine;
namespace window
{
class Console: public State
{ .. } }
WMesssage.hpp
...
class Engine;
namespace window
{
class Message: public State
{ ... } }
And all classes link to Engine class:
Engine.hpp
...
namespace window
{
class State;
class Console;
class Message;
}
class Engine
{
...
std::vector< std::unique_ptr<window::State> > m_windowObjects;
std::unique_ptr<window::Console> m_consoleWindow;
std::unique_ptr<window::Message> m_messageWindow;
...
}
And in Engine.cpp I include the headers:
#include "Engine.hpp"
#include "WState.hpp"
#include "WConsole.hpp"
#include "WMessage.hpp"
If I try to compile I get this errors:
In file included from /usr/include/c++/4.8.2/memory:81:0,
from /usr/local/include/SFGUI/Signal.hpp:6,
from /usr/local/include/SFGUI/Object.hpp:4,
from /usr/local/include/SFGUI/Widget.hpp:4,
from /usr/local/include/SFGUI/Container.hpp:4,
from /usr/local/include/SFGUI/Bin.hpp:4,
from /usr/local/include/SFGUI/SFGUI.hpp:6,
from ./include/Handler.hpp:4,
from main.cpp:1:
/usr/include/c++/4.8.2/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = window::Console]':
/usr/include/c++/4.8.2/bits/unique_ptr.h:184:16: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = window::Console; _Dp = std::default_delete<window::Console>]'
./include/Engine.hpp:21:7: required from here
/usr/include/c++/4.8.2/bits/unique_ptr.h:65:22: error: invalid application of 'sizeof' to incomplete type 'window::Console'
static_assert(sizeof(_Tp)>0,
^
/usr/include/c++/4.8.2/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = window::Message]':
/usr/include/c++/4.8.2/bits/unique_ptr.h:184:16: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = window::Message; _Dp = std::default_delete<window::Message>]'
./include/Engine.hpp:21:7: required from here
/usr/include/c++/4.8.2/bits/unique_ptr.h:65:22: error: invalid application of 'sizeof' to incomplete type 'window::Message'
From what I see I don't get an error relating to window::State so mean that I introduced it in the right way, but why I get error relating to window::Console and window::Message?
May affect that classes window::Console and window::Message are derivated from window::State?
I modified to shared_ptr, but including the headers are still a option.
Here is the link for someone who may have same error here
The type argument to unique_ptr must be a complete type for a lot of use cases (see comments for the details); a forward declared class is incomplete. You must have a full definition of the class visible.
Short answer:
explicitly write a destructor of Engine
and move the definition of Engine to the cpp of engine.
Long answer:
Lets see the preprocessing ( all includes are replaced with the content of their header )
and a bit of compiling.
Imagine the following:
//B.h
class A;
class B
{
std::unique_ptr<A> m_A;
public:
B();
};
//B.cpp
#include "B.h"
#include "A.h"
B::B()
: m_A(new A())
{
}
lets see B.i result file after executing the following command (g++ -std=c++11 B.cpp -E B.i):
class A;
class B
{
std::unique_ptr<A> m_A;
public:
B();
};
# 2 "B.cpp" 2
# 1 "A.h" 1
class A
{
public:
int mInt;
explicit A( int aInt = 0 )
: mInt(aInt)
{
}
};
# 3 "B.cpp" 2
B::B()
: m_A(new A())
{
}
Now comes the compiler part. According to cpp reference
If no user-declared prospective (since C++20)destructor is provided for a class type (struct, class, or union), the compiler will always declare a destructor as an inline public member of its class.
lets imagine the file with a declared destructor ( of course there will be declared copy constructor, assignment operator, but lets stick with destructor only )
class A;
class B
{
std::unique_ptr<A> m_A;
public:
B();
~B(){} // <-------- FOCUS HERE
};
# 2 "B.cpp" 2
# 1 "A.h" 1
class A
{
public:
int mInt;
explicit A( int aInt = 0 )
: mInt(aInt)
{
}
};
# 3 "B.cpp" 2
B::B()
: m_A(new A())
{
}
Notice the destructor there, and imagine that thats the place where the destruction of our unique_ptr object or any object will be called.
Realise that in that place our unique_ptr has no idea how to destroy A, since A is only forward declared. A is only defined few lines later, but the compiler can not see that. In order to make it compilable, we must force the destructor definition, to be after the definition of A.
this is simple, create an explicit destructor, and make sure its defined in the cpp file.