0

I am working on a clock display assignment and my professor wants us to use two classes, NumberDisplay and ClockDisplay. So in total I have two header and three cpp files. When I implemented the first part of the assignment using just the first class everything was fine. I noticed though that my professor wants us to declare a NumberDisplay object inside our ClockDisplay header. I figured just declaring like normal would work like this NumberDisplay hours = NumberDisplay(24); however I am not able to access the information unless I include the NumberDisplay.h file for my ClockDisplay.h. When I do that however I am assuming my errors are due to using #include <NumberDisplay.h> in both my NumberDisplay.cpp and my ClockDisplay.cpp. I just would like to know the proper way to structure my files so that I can properly create NumberDisplay objects in my ClockDisplay header file and then use said objects in my ClockDisplay cpp file.

2 Answers2

0

You can #include "NumberDisplay.h" within ClockDisplay.h. This will allow you to use NumberDisplay objects within your ClockDisplay's class declaration.

As a side note, be sure to use include guards for your headers. This will prevent the header from being included multiple times during compilation. Use #pragma once or

#ifndef NUMBERDISPLAY_H_
#define NUMBERDISPLAY_H_
...
#endif // NUMBERDISPLAY_H_
Sean Monroe
  • 173
  • 5
0

As user Sean Monroe pointed out about using header or include guards; this may not always be the full answer. This will help in many cases to fix your current problem but if you are not careful you can become a victim of circular includes.

Before I mention anything about that I will briefly describe the differences between #include <someheader.h> and #include "someheader.h". The first one will look where most of your system, os, and compiler and standard libraries files are located through the use of system environment variables that are setup by default through your IDE. The later will look in any immediate directories that are setup in the include paths for the current project with the root path being where the code lives when it is created if working in Visual Studio; other IDE's will more than likely be different, but the concept is still the same.

On circular includes: sometimes having header guards alone is not enough. Take for example:

file a.h

#ifndef A_H
#define A_H

#include "b.h"

class A {
private:
    B b;
public:
    explicit A( const B& b ) { ... }
};

#endif

file b.h

#ifndef B_H
#define B_H

#include "A.h"

class B {
public:
    explicit( A* pA ) { ... }
};

#endif

Here this would generate a circular include and this is something that is very important to be aware of. Regardless of which class A or B you try to create an object of in some other file, namespace, class or function the compiler will try to construct the first class and in order to do so it needs to construct the second class however when trying to construct the second class to complete the first class it goes back and tries to construct the first class again since the next requires the first which is an incomplete object and visa versa. This is not exactly a circular include per say but it is a circular infinite recursion of dependencies of incomplete classes. You can read this Q/A for more information: Resolve Circular Dependencies.

Sometimes it is not enough to just include the appropriate header of one class into the header of another; sometimes you may need to just declare a class prototype and or forward declaration in a class's header then include the header file within that class's cpp file. But this will usually work most often with pointers or references but not local copies since pointers and references are addressed by memory location that have a fixed size in memory. Example:

file A.h

#ifndef A_H
#define A_H

class B;

class A {
private:
    B* pB;
public:
    explicit A( const B& b );
}; 

#endif

file A.cpp

#include "A.h"
#include "B.h"

A::A( const B& b ) { ... }

file B.h

#ifndef B_H
#define B_H

#include "A.h"

class B {
public:
    B(){ ... }

    /*param type*/ someFunc( A* pA ) { /* do something with pA */ }
};

There are more problems than what are discussed here but you can read about them in some of the other answers to the same link that I provided above.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59