0

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

Jason
  • 36,170
  • 5
  • 26
  • 60
milanHrabos
  • 2,010
  • 3
  • 11
  • 45
  • Try a space between `class Grad` and `:` – infinitezero Dec 03 '21 at 10:01
  • @infinitezero didn't help – milanHrabos Dec 03 '21 at 10:03
  • @milanHrabos Try replacing **all** `` with `"c3/school/Core.hpp"`. That is instead of using `<>` for includes use "" . Do this for **every** custom included header. Just replace the surrounding `<>` with `""` in all the custom includes. – Jason Dec 03 '21 at 10:04
  • @AnoopRana I am using http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html , which discourages using `""` inclusion – milanHrabos Dec 03 '21 at 10:06
  • @milanHrabos Can you try replacing `#include ` with `#include "c3/school/Core.hpp"` in **Grad.hpp** and see if it works. This is a common issue while including files that is why i suggested it. Style guidelines are just that: guidelines. You don't necessarily have to follow them, especially if they result in some kind of error. – Jason Dec 03 '21 at 10:12
  • @AnoopRana well did not helped either – milanHrabos Dec 03 '21 at 10:15
  • @milanHrabos Ok then you need to add more information(like other files) and a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) so that we can narrow down the problem. In any case, i can say this with almost 100% certainty that the issue is because the class `Core` is not visible at the point when you write `class Grad: public Core` most probably because the compiler cannot find the file `Core.hpp` Also, take care of any cyclic dependencies(if any) in your complete project. – Jason Dec 03 '21 at 10:18
  • If the compiler could not find `Core.hpp` it would say so. So maybe it finds a different one. You could test this by putting an `#error` into your header file an see, whether the compiler chokes on the intentional error. – Xoozee Dec 03 '21 at 10:22
  • @AnoopRana I will crete githup repo and share the project here – milanHrabos Dec 03 '21 at 10:25
  • Include guards can also be trouble makers, so you should ensure there is no other definition of `C3_CORE_HPP` in your project. – Xoozee Dec 03 '21 at 10:25
  • @milanHrabos Yes create a github repo and share the link, that will definitely tell us the problem whether it is with header guards or includes etc. – Jason Dec 03 '21 at 10:27
  • @AnoopRana github repo: https://github.com/Herdsmann/student_project.git – milanHrabos Dec 03 '21 at 10:47
  • @Xoozee github repo: https://github.com/Herdsmann/student_project.git – milanHrabos Dec 03 '21 at 10:47
  • The problem is, that Core.hpp defines `C3_GRAD_HPP` and includes Student.hpp, which includes Grad.hpp, which now wants to include Core.hpp again. Since this time `C3_GRAD_HPP` is already defined, the inclusion succeeds, but the file content is skipped by the preprocessor. That's why `Core` is not known, when `Grad` is defined. – Xoozee Dec 03 '21 at 10:58
  • @infinitezero -- no, a space before `:` isn't required. Try it. – Pete Becker Dec 03 '21 at 14:08
  • @milanHrabos -- concerning that paper, I'd give it a wide berth. Just because somebody wrote it, doesn't mean it's a good thing. Yes, the search rules for `"..."` fall back to `<...>` if the first part of the search doesn't find the file. No, that's not a problem; the rationale presented in the paper is that the compiler might end up finding some unrelated file if the one you want doesn't exist, but that's the case either way. – Pete Becker Dec 03 '21 at 14:12
  • @PeteBecker agreed. But I was looking for canonical project structure anyway. For now I am using that paper which so far made sense for me. Later I will read https://www.pearson.com/store/p/large-scale-c-volume-i-process-and-architecture/P100001343596/9780201717068 – milanHrabos Dec 03 '21 at 16:36

2 Answers2

2

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.hpp. 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 
Jason
  • 36,170
  • 5
  • 26
  • 60
0

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
Xoozee
  • 370
  • 2
  • 9