Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Newbie problem

57 views
Skip to first unread message

Doug Mika

unread,
Mar 26, 2015, 12:54:36 PM3/26/15
to
Hi, I have defined a class called TimeType.cc and DateType.cc. Inside my DateType.cc class I use the TimeType object and inside my TimeType.cc class I use the DateType object. For some reason my compiler complains with the following message:
In file included from DateType.h:11:0,
from DateType.cc:8:
TimeType.h:21:26: error: 'DateType' has not been declared

I've attached the files below: (ANY help is appreciated)
*****DateType.h*******
#ifndef DATETYPE_H
#define DATETYPE_H

#include "TimeType.h"

class DateType {
public:
DateType();
DateType(const DateType& orig);
virtual ~DateType();
void setDate(TimeType time);
private:
int day;
int month;
int year;

};

#endif /* DATETYPE_H */

*******TimeType.h*********
#ifndef TIMETYPE_H
#define TIMETYPE_H

#include "DateType.h"

class TimeType{
public:
void Set(int hours, int minutes, int seconds);
void Increment();
void Write() const;
bool Equal(TimeType otherTime) const;
bool LessThan(TimeType otherTime) const;
void setTimeFromDate(DateType date);
private:
int hrs;
int mins;
int secs;
};

#endif /* TIMETYPE_H */

*********DateType.cc************
#include "DateType.h"


DateType::DateType() {
}

DateType::DateType(const DateType& orig) {
}

DateType::~DateType() {
}

void DateType::setDate(TimeType time){

}

********TimeType.cc***********
#include <iostream>
#include "TimeType.h"

using namespace std;

void TimeType::Set(int hours, int minutes, int seconds){
hrs = hours;
mins = minutes;
secs = seconds;
}

void TimeType::Increment(){
secs++;
if (secs>59){
secs = 0;
mins++;
if(mins>59){
mins=0;
hrs++;
if(hrs>23)
hrs=0;
}
}
}

void TimeType::Write() const{
if(hrs<10) cout<<'0';
cout<<hrs<<':';
if(mins<10) cout<<'0';
cout<<mins<<':';
if(secs<10) cout<<'0';
cout<<secs;
}

bool TimeType::Equal(TimeType otherTime) const{
return (hrs==otherTime.hrs && mins == otherTime.mins && secs==otherTime.secs);
}

bool TimeType::LessThan(TimeType otherTime) const{
return ((hrs < otherTime.hrs) ||
(hrs == otherTime.hrs && mins<otherTime.mins) ||
(hrs==otherTime.hrs && mins==otherTime.mins && secs<otherTime.secs));
}

void TimeType::setTimeFromDate(DateType date){

}

*********And the file with the main method - welcome.cc*********
#include <iostream>
#include <fstream>
#include <math.h>
#include <float.h>
#include <cstdio>
#include <string.h>
#include "TimeType.h"

int main(int argc, char**argv) {
// Prints welcome message...
std::cout << "Welcome ..." << std::endl;

ifstream in;
ofstream out;
int i;

int count=2;
double testVar = 325;
string fname, lname;
char testName[20];
bool boolVar;
TimeType time1;
time1.Set(1,2,3);
time1.Write();
//char fname[10];

//out.open("output.dat");

// Prints arguments...
std::cout<<"Command Parameters: "<<std::endl;
if (argc > 1) {
std::cout << std::endl << "Arguments:" << std::endl;
for (int i = 1; i < argc; i++) {
std::cout << i << ": " << argv[i] << std::endl;
}
}

cout<<"Enter the output file name: ";
//cin.get(fname,10);
//cin.ignore(100, '\n');
cin>>fname;
out.open(fname.c_str());
//testName="Marcin";
strcpy(testName, "Marcin");

user user_one, user_two;
out<<"The user id of \"user_one\" is: "<<user_one.get_user_id()<<endl;
out<<"The user id of \"user_two\" is: "<<user_two.get_user_id()<<endl;
cout<<"The next user ID is: "<<user::next_user_id()<<endl;
cout<<"The next user ID is: "<<user::next_user_id()<<endl;
cout<<"Test: "<<test(fname)<<endl;



return 0;
}


int test(const string name){
int i=0;

while(name[i]!='\0')
i++;
cout<<"Inside test:"<<i<<endl;
return i;
}

Christopher Pisz

unread,
Mar 26, 2015, 1:13:10 PM3/26/15
to
You have a circular inclusion. That is generally frowned upon and points
to a design problem. If a circular inclusion is indeed necessary, you
can resolve it by using a forward declaration in one of the headers and
make the member a pointer. Then include the file in the cpp where the
pointer is assigned to an actual object.

See the C++ FAQ at
http://isocpp.org/wiki/faq/misc-technical-issues#forward-decl

Also, unless this is an academic exercise, I would highly recommend
avoiding the creation of your own time and date types. There are so many
out there already and all of them are bound to work better and be more
bug free. Check out boost::posix_time::ptime and boost::gregorian::date
for example.



--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---

Öö Tiib

unread,
Mar 26, 2015, 6:25:30 PM3/26/15
to
On Thursday, 26 March 2015 19:13:10 UTC+2, Christopher Pisz wrote:
>
> Also, unless this is an academic exercise, I would highly recommend
> avoiding the creation of your own time and date types. There are so many
> out there already and all of them are bound to work better and be more
> bug free. Check out boost::posix_time::ptime and boost::gregorian::date
> for example.

For novice it might be better idea to first learn to use the date
and time related things that are available in C++ library.
For most things <chrono> and <ctime> or <time.h> are plenty.

Boost.Date_Time is fine but might be slightly too heavyweight for
common needs. It even isn't totally header only (something about
serialization is in library) and so at least Microsoft compilers
tend to give linker errors if we do not put
'#define BOOST_DATE_TIME_NO_LIB' before including its headers.


Louis Krupp

unread,
Mar 27, 2015, 2:16:04 PM3/27/15
to
1. As a general rule, post the smallest piece of code that reproduces
the problem. Your situation can be demonstrated by something like
this:

===
class a
{
void f(b& x);
};

class b
{
void f(a& x);
};
===

Nothing you can do with header files changes the fact that 'b' hasn't
been declared when it's used in class 'a'. The solution is a forward
declaration:

===
class b;

class a
{
...
};
===

2. For your own sanity, as well as for everyone else who reads your
code, don't include user header files within other user header files.
This is a style issue; it's more work up front, but I think it makes
the code easier to read and maintain.

Louis

Cholo Lennon

unread,
Mar 27, 2015, 3:58:31 PM3/27/15
to
This is not exactly the same situation the OP has: He isn't using
pointers or references in order to use a forward declaration to solve
his problem.


> 2. For your own sanity, as well as for everyone else who reads your
> code, don't include user header files within other user header files.
> This is a style issue; it's more work up front, but I think it makes
> the code easier to read and maintain.
>



Regards

--
Cholo Lennon
Bs.As.
ARG

Paavo Helde

unread,
Mar 27, 2015, 4:58:50 PM3/27/15
to
Doug Mika <doug...@gmail.com> wrote in
news:9cdc42da-7317-425e...@googlegroups.com:

class DateType {
> void setDate(TimeType time);

> class TimeType{
> void setTimeFromDate(DateType date);

Here is your problem. Even if you get this compiling with forward
declarations, you still have the conceptual problem. How do you think it is
possible to convert a 24-hour time to a date, or vice versa? They have
nothing in common.

As these types are not related in any way, both of them should not include
the header of the other, and when they do not your concern of circular
includes will just go away.

hth
Paavo

Doug Mika

unread,
Mar 27, 2015, 5:15:37 PM3/27/15
to
I was trying to illustrate the point that the compiler complains when Class A includes Class B and class B includes class A. I wanted to know how to get around it. Now I know...forward declerations...thanks to all (The code was not meant to be "logical" merely trying to illustrate a purpose) Also, I heard you should have classes that include each other...that's probably true - at least I haven't come up with a situation yet where such could be useful

Again, thanks to all

Doug

Louis Krupp

unread,
Mar 27, 2015, 8:39:00 PM3/27/15
to
On Fri, 27 Mar 2015 14:13:45 -0700 (PDT), Doug Mika
<doug...@gmail.com> wrote:

>I was trying to illustrate the point that the compiler complains when Class A includes Class B and class B includes class A. I wanted to know how to get around it. Now I know...forward declerations...thanks to all (The code was not meant to be "logical" merely trying to illustrate a purpose) Also, I heard you should have classes that include each other...that's probably true - at least I haven't come up with a situation yet where such could be useful

I would use the word "reference" or "use" rather than "include";
"include" implies "#include", which is probably not what you meant.

A forward declaration might be useful if you had, for example,
Cartesian coordinates and polar coordinates and you wanted conversion
functions to transform one to the other:

// to be put in cartesian.h with appropriate #ifndef/#endif
class polar;

class cartesion
{
public:
operator polar(); // implementation left as an exercise
private:
double x, y;
};

// to be put in polar.h with appropriate #ifndef/#endif
class cartesian;

class polar
{
public:
operator cartesion(); // implementation left as an exercise
private:
double r, theta;
};

// main.cxx (or whatever your extension is)
// #include order shouldn't matter
#include "cartesian.h"
#include "polar.h"

void do_little()
{
cartesian c;
polar p;

...

c = p; // same as c = cartesian(p);
p = c; // same as p = polar(c);

...
}

This is a stub. I've done only minimal testing. I hope it helps. If
I've gotten this seriously wrong, I'm sure someone will say so.

Louis

Richard Damon

unread,
Mar 27, 2015, 9:31:01 PM3/27/15
to
You actually have a slightly tougher problem, as class A has a member
function that takes a B "by value" and class B has a member function
that takes an A "by value". C++ requires that you can pass a pointer to
an incomplete type, as all struct/class pointers use a compatible
representation. Passing an object by value requires the use of the class
copy constructor, and more detailed knowledge of the class, so it can't
be done with a "forward" declaration.

This presents a fundamental issue with your design, as you now need a
full definition of B to define A, and a full definition of A to define
B, so neither can be defined. You need to break the cycle. Options include:

1) Change at least one of the pass by values with a pass by reference
(or const reference) to break the cycle, the one(s) using reference can
use a forward declare.

2) One or more of the member functions can be converted into free
functions and moved to a new header (or the classes moved to a new
header). The class headers no longer have the circular dependency, and
the headers with the free functions can include both class headers.
0 new messages