having this base class:
Core.hpp:
#ifndef C3_CORE_HPP
#define C3_CORE_HPP
#include <c3/utils/Str.hpp>
#include <c3/utils/Vec.hpp>
#include <c3/school/Student.hpp>
class Core {
public:
Core() = default;
explicit Core(std::istream&in);
virtual ~Core();
virtual double grade() const;
const Str &getName() const;
double getMidterm() const;
double getFinal() const;
const Vec<double> &getHomeworks() const;
protected:
Vec<double> homeworks;
virtual std::istream &read(std::istream &in);
virtual Core *clone() const;
std::istream &read_common(std::istream &in);
private:
Str name;
double midterm{}, final{};
friend class Student;
};
std::istream &read_hw(std::istream &in, Vec<double> &hws);
#endif //C3_CORE_HP
and Grad.hpp:
#ifndef C3_GRAD_HPP
#define C3_GRAD_HPP
#include <c3/school/Core.hpp>
class Grad: public Core {
public:
Grad() = default;
explicit Grad(std::istream &in);
std::istream &read(std::istream &in) override;
double grade() const override;
protected:
Grad *clone() const override;
private:
double thesis{};
};
#endif //C3_GRAD_HPP
(The code is created according to book accelerated C by Andrew Koenig)
Now this gets me error:
In file included from /home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Student.hpp:8,
from /home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Core.hpp:10,
from /home/shepherd/Desktop/cpp/cpp0book/c3/c3/main.cpp:4:
/home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Grad.hpp:10:25: error: expected class-name before ‘{’ token
10 | class Grad: public Core {
| ^
/home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Grad.hpp:15:19: error: ‘std::istream& Grad::read(std::istream&)’ marked ‘override’, but does not override
15 | std::istream &read(std::istream &in) override;
| ^~~~
/home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Grad.hpp:16:12: error: ‘double Grad::grade() const’ marked ‘override’, but does not override
16 | double grade() const override;
| ^~~~~
/home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Grad.hpp:19:11: error: ‘Grad* Grad::clone() const’ marked ‘override’, but does not override
19 | Grad *clone() const override;
| ^~~~~
In file included from /home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Core.hpp:10,
from /home/shepherd/Desktop/cpp/cpp0book/c3/c3/main.cpp:4:
/home/shepherd/Desktop/cpp/cpp0book/c3/./c3/school/Student.hpp:26:5: error: ‘Core’ does not name a type
26 | Core *cp{};
| ^~~~
gmake[2]: *** [CMakeFiles/c3.dir/build.make:76: CMakeFiles/c3.dir/c3/main.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/c3.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2
The first error is
error: expected class-name before ‘{’ token
10 | class Grad: public Core {
Which seems to me the compiler cannot recognize the Core
class even when included. So why cannot compiler recognize my base class?
using this directory structure: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html
github repo: https://github.com/Herdsmann/student_project.git
CodePudding user response:
As i said in the comment, the problem is due to cyclic dependency. In particular, your
Student.hpp includes --> Grad.hpp which in turn includes --> Core.hpp which finally includes --> Student.hpp
So as you can see from above, you ended up where you started, namely at Student.cpp. This is why it is called cyclic dependency.
To solve this just remove the #include <c3/school/Student.hpp>
from Core.hpp. This is because for the friend declaration friend class Student
, you don't need to forward declare or include the Student
class.
So the modified/correct Core.hpp file looks like this:
#ifndef C3_CORE_HPP
#define C3_CORE_HPP
#include <c3/utils/Str.hpp>
#include <c3/utils/Vec.hpp>
//note i have removed the include header from here
class Core {
//other members here as before
private:
Str name;
double midterm{}, final{};
friend class Student;//THIS WORKS WITHOUT INCLUDING Student.hpp
};
std::istream &read_hw(std::istream &in, Vec<double> &hws);
#endif //C3_CORE_HPP
CodePudding user response:
In the git repository the file main.cpp
is including Core.hpp
, which includes Student.hpp
to get a definition for the friend class Student. In the file Student.hpp
the header Grad.hpp
is included, which itself includes Core.hpp
. Now, since Core.hpp
defines the include guard C3_CORE_HPP
before including Student.hpp
, the content of Core.hpp
is skipped by the preprocessor, when included by Grad.hpp
. That's why the class Core
is not known to the compiler, when the class Grad
is defined.
To resolve this, you can predefine the class Student
in Core.hpp
and omit the inclusion:
Core.hpp:
#ifndef C3_CORE_HPP
#define C3_CORE_HPP
#include <c3/utils/Str.hpp>
#include <c3/utils/Vec.hpp>
class Student;
class Core {
// [...]
friend class Student;
};
std::istream &read_hw(std::istream &in, Vec<double> &hws);
#endif //C3_CORE_HP