Thread: incomplete type error despite complete definition

  1. #1
    Registered User
    Join Date
    Dec 2007
    Location
    Germany
    Posts
    30

    incomplete type error despite complete definition

    Hello,
    i'm frustrating a bit with the following errors and warnings. Despite including the right header properly (at least i hope so), the compiler is complaining about incomplete/undefined types. There should also be no semicolons missing. The error messages, here you go, great thanks for all help:

    cyear.h: In destructor ‘cyear::~cyear()’:
    cyear.h:52: warning: possible problem detected in invocation of delete operator:
    cyear.h:52: warning: invalid use of undefined type ‘struct cmonth’
    cyear.h:12: warning: forward declaration of ‘struct cmonth’
    cyear.h:52: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
    cyear.h: In member function ‘bool cyear::read_months()’:
    cyear.h:65: error: invalid use of undefined type ‘struct cmonth’
    cyear.h:12: error: forward declaration of ‘struct cmonth’

    You may be interested in the code, too:

    cyear.h - critical parts are marked
    Code:
    #ifndef CYEAR_H
    #define CYEAR_H
    
    #include <iostream>
    using std::cout;
    using std::endl;
    
    #include <list>
    using std::list;
    
    #include "cmonth.h"
    class cmonth;
    
    struct syear{
      short int events;
      char main_event[256];
    };
    
    struct sweek{
      short int events;
      char main_event[256];
    };
    
    struct sday{
      short int events;
      char main_event[256];
    };
    
    struct stime{
      short int hour;
      short int minute;
      char event[256];
    };
    
    class cyear{
      private:
        int year;
        list<cmonth*> cmonths;
        syear this_year;
      public:
        cyear(int _year): year(_year){
          furz hallo();
          if(!read_year(year, this_year)){
            this_year.events = 0;
            strcpy(this_year.main_event, "");
          }
        }
    
        ~cyear(){
          while(!cmonths.empty()){
            delete cmonths.back();
            cmonths.pop_back();
          }
        }
    
        bool read_year(int _year, syear& the_year);
        void write_year(int _year, syear& the_year);
        void write_year(){
          write_year(year, this_year);
        }
    
        bool read_months(){
          for(int i = 1; i < 13; i++){
            cmonths.push_back(new cmonth(i, *this));
          }
        }
    
        int get_year(){ return year; };
    
        void set_event(char event[]); 
    
        void inc_events(){ this_year.events++; }
    
        void print();
        
        static bool is_leap_year(int _year);
    
        bool is_leap_year(){ is_leap_year(year); }
    
        static int doomesday(int _year){
          return (2 + _year + (_year/4) - (_year/100) + (_year/400))%7;
        }
    
        int doomesday(){ doomesday(year); }
    
      friend class cmonth;
    };
    
    #endif
    ...and cmonth.h
    Code:
    #ifndef CMONTH_H
    #define CMONTH_H
    
    #include "cyear.h"
    #include "cweek.h"
    #include "cday.h"
    
    #include <iostream>
    using std::cout;
    using std::endl;
    
    #include <list>
    using std::list;
    
    struct smonth{
      short int events;
      char main_event[256];
    };
    
    class cyear;
    #include "cyear.h"
    
    class cmonth{
      private:
        int month;
        list<cweek*> cweeks;
        list<cday*> cdays;
        smonth this_month;
        cyear& the_year;
      public:
        cmonth(int _month, cyear& _the_year): month(_month),
                                              the_year(_the_year){
          if(!read_month(month, this_month)){
            this_month.events = 0;
            strcpy(this_month.main_event, "");
          }
        }
    
        ~cmonth(){
        }
    
        bool read_month(int _month, smonth& the_month);
        void write_month(int _month, smonth& the_month);
        void write_month(){
          write_month(month, this_month);
        }
    
        void set_event(char event[]); 
    
        void inc_events(){ this_month.events++; }
    
        void print();
    };
    
    #endif
    If something is unclear, please ask, I know that it is a lot code for a post.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Code:
    class cyear;
    #include "cyear.h"
    If you include the appropriate header, you don't need a forward declaration.
    Similarly, you don't need a forward declaration AFTER you include the correct header, which can give you problems apparently.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Registered User
    Join Date
    Dec 2007
    Location
    Germany
    Posts
    30
    Thanks for your help, i removed all forward declarations, but this made it even worse. Now the compiler claims that cyear wasn't declared although i included the header (see above, i didn't change it). Here are lots of funny errors, depending on each other:

    cmonth.h:28: error: ISO C++ forbids declaration of ‘cyear’ with no type
    cmonth.h:28: error: expected ‘;’ before ‘&’ token
    cmonth.h:30: error: ‘cyear’ has not been declared
    cmonth.h: In constructor ‘cmonth::cmonth(int, int&)’:
    cmonth.h:31: error: class ‘cmonth’ does not have any field named ‘the_year’
    cyear.h: In member function ‘bool cyear::read_months()’:
    cyear.h:62: error: no matching function for call to ‘cmonth::cmonth(int&, cyear&)’
    cmonth.h:30: note: candidates are: cmonth::cmonth(int, int&)
    cmonth.h:22: note: cmonth::cmonth(const cmonth&)
    cyear.h:37: error: ‘cmonth’ was not declared in this scope
    cyear.h:37: error: template argument 1 is invalid
    cyear.h:37: error: template argument 2 is invalid
    cyear.h: In destructor ‘cyear::~cyear()’:
    cyear.h:48: error: request for member ‘empty’ in ‘((cyear*)this)->cyear::cmonths’, which is of non-class type ‘int’
    cyear.h:49: error: request for member ‘back’ in ‘((cyear*)this)->cyear::cmonths’, which is of non-class type ‘int’
    cyear.h:50: error: request for member ‘pop_back’ in ‘((cyear*)this)->cyear::cmonths’, which is of non-class type ‘int’
    cyear.h: In member function ‘bool cyear::read_months()’:
    cyear.h:62: error: request for member ‘push_back’ in ‘((cyear*)this)->cyear::cmonths’, which is of non-class type ‘int’
    cyear.h:62: error: expected type-specifier before ‘cmonth’
    cyear.h:62: error: expected `)' before ‘cmonth’
    cmonth.h:28: error: ISO C++ forbids declaration of ‘cyear’ with no type
    cmonth.h:28: error: expected ‘;’ before ‘&’ token
    cmonth.h:30: error: ‘cyear’ has not been declared
    cmonth.h: In constructor ‘cmonth::cmonth(int, int&)’:
    cmonth.h:31: error: class ‘cmonth’ does not have any field named ‘the_year’
    cyear.h: In member function ‘bool cyear::read_months()’:
    cyear.h:62: error: no matching function for call to ‘cmonth::cmonth(int&, cyear&)’
    cmonth.h:30: note: candidates are: cmonth::cmonth(int, int&)
    cmonth.h:22: note: cmonth::cmonth(const cmonth&)

  4. #4
    Registered User
    Join Date
    Dec 2007
    Posts
    6
    Hi mate,

    Your code compiled fine for me (i did have to comment out references to cweek and cday though). I think Elysia is right, it feels like a forward declaration problem to me.

    I commented out #include "cyear.h" in cmonth but left in the forward declarion class cyear ; and it worked fine.

    Try that and let us know if you're still having problems

  5. #5
    Registered User
    Join Date
    Dec 2007
    Location
    Germany
    Posts
    30
    Lots of thanks to both of you. You really helped me out of it, now all works fine.
    By the way:
    Merry Christmas to whom it may concern,
    Ben
    Last edited by benshi; 12-24-2007 at 08:53 AM.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Cmonth.h and cyear.h both include each other, so you have circular references. Therefore, you must use a forward declaration in one of the files and that include should be removed. Include the appropriate header in the .cpp file and it will work fine.
    You could remember that little lesson until the next it appears for you
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Code:
    #include "cmonth.h"
    class cmonth;
    Why are you adding a forward declaration right after you include the header that contains a complete declaration?
    I've never tried that, but I'm guessing it would clobber the cmonth declaration that you just included.

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Do you have a specific reason for putting the implementation in the header files? If you put the implementation in a source file for both cmonth and cyear, then you could use only forward declarations in the header file. This is preferred because changes to those classes' interfaces wouldn't affect each other.

    Prefer a forward declaration rather than a header include if you can do it. In this case, the class declarations require only a forward declaration.

  9. #9
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The forward declaration is not a problem by itself, merely a symptom. The recursive include is the real problem.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  10. #10
    Registered User
    Join Date
    Dec 2007
    Location
    Germany
    Posts
    30
    Great thanks to all of you, your explainations and suggestions are very helpful, letting me understand the code a bit better. I agree that it would be easier to put all implementations in the apropriate source file.
    Ben

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sorting the matrix question..
    By transgalactic2 in forum C Programming
    Replies: 47
    Last Post: 12-22-2008, 03:17 PM
  2. strings Vs. Char pointers
    By aijazbaig1 in forum C Programming
    Replies: 49
    Last Post: 02-13-2008, 09:51 AM
  3. Script errors - bool unrecognized and struct issues
    By ulillillia in forum Windows Programming
    Replies: 10
    Last Post: 12-18-2006, 04:44 AM
  4. Replies: 28
    Last Post: 07-16-2006, 11:35 PM
  5. Question on l-values.
    By Hulag in forum C++ Programming
    Replies: 6
    Last Post: 10-13-2005, 04:33 PM