0

I want to create a class Student that has a member of type library std::string but I don't want to include the header <string> in my Student.h and use only forward-declaration:

// Student.h
#ifndef STUDENT_H
#define STUDENT_H

#include <iostream>

typedef class string_ string;

struct Student
{
public:
    Student(const string_&, std::size_t);
    const string_ name()const;
    void setName(const string_&);
    std::size_t age()const;
    void setAge(std::size_t);
private:
    string_* name_ ;
    std::size_t age_;
};

 // Student.cpp
#include "Student.h"
#include <string>

Student::Student(const std::string& str, std::size_t a) :
    name_(&str),
    age_(a)
{}
  • When I compile the program I get these errors: ../src/Student.cpp:13:2: error: no declaration matches ‘Student::Student(const string&, std::size_t)’ 13 | Student::Student(const std::string& str, std::size_t a) :

  • So can I use forward declaration so that in a header I don't include any header but just forward-declare for the types I need then in source I include the headers?

  • I've done this because I'm reading Mastering Qt5 book by Guillaume Lazar in which he gave this example:

    //SysInfoWindowsImpl.h
    #include <QtGlobal>
    #include <QVector>
    #include "SysInfo.h"
    
    
    typedef struct _FILETIME FILETIME;
    
    class SysInfoWindowsImpl : public SysInfo
    {
    public:
        SysInfoWindowsImpl();
        void init() override;
        double cpuLoadAverage() override;
        double memoryUsed() override;
    private:
        QVector<qulonglong> cpuRawData();
        qulonglong convertFileTime(const FILETIME& filetime) const;
    private:
        QVector<qulonglong> mCpuLoadLastValues;
    };
    
    //SysInfoWindowsImpl.cpp
    #include "SysInfoWindowsImpl.h"
    #include <windows.h>
    
    
    SysInfoWindowsImpl::SysInfoWindowsImpl() :
        SysInfo(),
        mCpuLoadLastValues()
    {
    }
    
    void SysInfoWindowsImpl::init()
    {
        mCpuLoadLastValues = cpuRawData();
    }
    
    qulonglong SysInfoWindowsImpl::convertFileTime(const FILETIME& filetime) const
    {
        ULARGE_INTEGER largeInteger;
        largeInteger.LowPart = filetime.dwLowDateTime;
        largeInteger.HighPart = filetime.dwHighDateTime;
        return largeInteger.QuadPart;
    }
    

"The syntax typedef struct _FILETIME FILETIME is a kind of forward declaration for FILENAME syntax. As we only use a reference, we can avoid including the tag in our file SysInfoWindowsImpl.h and keep it in the CPP file." from the book.

  • So can someone explain to me how could he use typedef struct _FILETIME which is defined in windows.h? Thank you.
Maestro
  • 2,512
  • 9
  • 24
  • 1
    `typedef class string_ string;` - that's not a forward declaration. And I'd shy away from aliases like that. They will bite you at some point. – Jesper Juhl May 07 '20 at 17:24
  • @JesperJuhl: I saw an example this way in Qt book: `typedef struct _FILETIME FILETIME;` what do you think? – Maestro May 07 '20 at 17:28
  • 1
    I think that I have no idea what you are asking. Do you understand what that line of code does? Are you asking why that makes sense in Qt? Are you just copy'n'pasting stuff you've seen elsewhere in the hope it will fix your issue but without really understanding it (my current guess)? – Jesper Juhl May 07 '20 at 17:31

2 Answers2

3

Yes, but only if they match.

You forward declared a global type string, not in namespace std.

You could probably make it work with namespace std {} but then your program would have undefined behaviour, because you're not allowed to declare new things in that namespace (with a few exceptions).

In general, you want to avoid forward declarations for anything but your own classes.

Just #include <string>. If doing so is causing problems, you should resolve those independently.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • Why in th book of Qt5 he forward declares `typedef struct _FILETIME FILETIME; which is defined in `windows.h` header? ` – Maestro May 07 '20 at 17:39
  • 2
    @Maestro: (A) Because `FILETIME` is in the global namespace, and not the `std` namespace, so it works, and (B) because you're allowed to declare things in the global namespace. You're not allowed to declare things in the `std` namespace – Mooing Duck May 07 '20 at 17:41
  • @MooingDuck: You mean `FILETIME` not `FILENAME`? – Maestro May 07 '20 at 17:42
  • 1
    Yes, sorry about my typo – Mooing Duck May 07 '20 at 17:43
  • @MooingDuck: Thank you. – Maestro May 07 '20 at 17:44
  • So you mean we can forward declare types defined in windows.h because they are in global namespace which I think so as the writer of the book do by forwarding `struct _FILETIME`. I've created for educational purpose my String class in `String.h` and implemented in `String.h` and in my `Student.h` I've juse used forward-declaration for my type `String` without including `String.h` and in `Student.cpp` I've included both headers `String.h` and `Student.h` and everything is Ok. Thank you! – Maestro May 07 '20 at 21:46
-1

No, you cannot today (in may 2020). See also this and n3337 (the C++11 standard).

But C++20 or later might add modules, and then things become different.

Practically speaking, for a small program (e.g. less than a few dozen thousands lines of your C++ code) a common approach is to have a single header file -which you would #include in each of your translation units, and that common master header file would #include many standard headers. With recent GCC, you could use precompiled headers (and practically speaking, that works the best with a single master header, perhaps #include -ing sub header files; see this explanation)

Consider also using a good enough build automation toolset. On Linux, that might be a combination of GCC or Clang, ccache, with make or ninja, etc...

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 3
    I don't think recommending a "god header" is a good idea. Even for small projects. It leads to laziness regarding including only what you use, and small projects tend to grow large over time and then the bad habits start biting bad and require a lot of effort to clean up. – Jesper Juhl May 07 '20 at 17:20
  • @Jesper Juhl: What is the problem with large files? I routinely have files of more than 10 KLOC, and if I look inside the source code of GCC, they are also doing that. Some of my C or C++ files are generated, and they could be even bigger. Of course, you need a good enough editor (like `emacs`) – Basile Starynkevitch May 07 '20 at 17:33
  • I've edited the topic would you like to pay a look,? thanks – Maestro May 07 '20 at 17:34
  • 1
    @BasileStarynkevitch The problem is not with large files. The problem is with many files including more headers than they need. The project I work on used to take ~20min to compile on a 20 core Xeon CPU with HT. When we did an effort to cut down on pointless includes, that time dropped to roughly half (yeah, it was bad, lots of God headers etc). – Jesper Juhl May 07 '20 at 17:38
  • But 20 minute build is a short time. Try building [Qt](http://qt.io/) or [Firefox](https://www.mozilla.org/en-US/firefox/new/) or [Libreoffice](https://libreoffice.org/) from its source code. On a powerful desktop, that takes more than a night. – Basile Starynkevitch May 07 '20 at 17:39
  • And [GCC](http://gcc.gnu.org/) or [Clang](http://clang.llvm.org/) -both are C++ compilers- is coded in C++ and takes more than 20 minutes to be built. – Basile Starynkevitch May 07 '20 at 17:41
  • 4
    @BasileStarynkevitch I have built Qt from source. Many times. Yes, that's slow, but how is that relevant to not slowing your build down more than you have to by including pointless stuff? – Jesper Juhl May 07 '20 at 17:42
  • With `ccache` and precompiled headers the build time of a 30KLOC source program stays quite acceptable. Yes, C++ needs modules. And no, hundreds of tiny files (e.g. of 200 lines each) is *not* the solution. BTW, we both know that C++ sucks. It stays useful. – Basile Starynkevitch May 07 '20 at 17:42
  • But I've defined my class `String` in another header `String.h` and use just forward declaration and worked fine?! – Maestro May 07 '20 at 21:35
  • @JesperJuhl: I've managed to get it work: I've created a class `String` in `String.h` and the definition in `String.cpp` and in `Student.h` I've used `typedef class String String_;` and used `String` in my Student header as an incomplete type and in the source `Student.cpp` I've included `String.h` and everything works fine! That is what said in Qt5 book to avoid pointless inclusion of headers in other header. – Maestro May 07 '20 at 21:38