Thread: Preprocessor inclusion errors -- What do you mean I haven't declared it?!

  1. #1
    Registered User
    Join Date
    Apr 2011
    Posts
    2

    Preprocessor inclusion errors -- What do you mean I haven't declared it?!

    Recently, I have been trying to break out of some bad coding habits. I have been trying to improve my coding style and my over all program design and organization. One of my bad habits has been writing everything in header files and simply including them in main.cpp. By this, I mean that main.cpp has been my only source file, and every other file in my project has been a header.

    Clearly, this is a problem, and I am trying to break out of it and write my future projects with separate source files and headers for each class. However, because I am not accustomed to breaking up my files in this way (and because I never learned the correct way to do it), I am having trouble.

    My current understanding is that I write the class declaration in the header file, for example:

    MyClass.h

    Code:
    #ifndef __MYCLASS_H__
    #define __MYCLASS_H__
    
      class MyClass {
    
        private:
        int a_, b_, c_;
    
        public:
        MyClass();
        int getA(void);
        int getB(void);
        int getC(void);
    };
    
    #endif /* __MYCLASS_H__ */

    And then write the method definitions in a *.CPP file which includes the *.H file, like so:

    MyClass.cpp
    Code:
    #include "myclass.h"
    
    
      MyClass::MyClass() {
        a_ = 54;
        b_ = 92;
        c_ = 0;
      }
    
      int MyClass::getA(void) {
        return a_;
      }
    
    
      int MyClass::getB(void) {
        return b_;
      }
    
    
      int MyClass::getC(void) {
        return c_;
      }
    This is all well and good -- the code compiles and runs as expected. It even works fine when I want to use another object -- I simply include its header file in the source file of the object I want to use with it. Oddly enough, however, once my project comes to involve more than three or four objects, I encounter some very frustrating compile time errors. They will either claim I've declared something twice (despite my careful wrapping of headers such that they can't be compiled twice), or they will claim the opposite -- that I have failed to declare the object in question at all. Please note that while I am not above simply overlooking something obvious, I have been doing this for a while and have a decent idea of how preprocessor directives work -- I realize that the order in which files are included matters.

    Some of the errors I have gotten have included "[class name] is not a type",
    "ISO C++ forbids declaration of [class name] without a type" (apparently it thinks I'm trying to declare a variable, when in fact I'm trying to declare an object of the type it thinks is the variable name), as well as errors claiming I have multiple declarations of the same class. Adding extra inclusion directives at different places has hit-and-miss effectiveness, adding empty classes of the same name as the ones being ignored, such as:
    Code:
      class MyClass {
               };
    amusingly will cause the compiler to act as though the empty class was declared first (although the inclusion directive which includes the file that has the real class declaration in it is right ABOVE the empty class).

    Bottom line, I don't know everything, clearly, but I'm not stupid. I don't understand what's going on here. My IDE is the latest (buggy) version of Dev-Cpp, and my compiler is the GNU compiler that I downloaded alongside Dev.

    Thank you for reading, and any help would be greatly appreciated.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Post the smallest and simplest program that demonstrates the problem, and state the exact error message.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    A guess would be that you have a file A.h which includes B.h, which includes A.h, ...
    This obviously cannot work. For that you need forward declarations.
    Nevertheless, I would agree that it might be best to post a sample that demonstrates the problem as we cannot be sure this is the case.
    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.

  4. #4
    Registered User
    Join Date
    Apr 2011
    Posts
    2
    I have written up a quick sample program that demonstrates one of the messages I get -- but I think it would take too long to figure out how to write one that demonstrates all of the problems I'm having.

    class1.h

    Code:
      class Class1 {
        private:
        int a_;
        public:
        Class1();
        int  getA(void);
        void setA(int a);
      };
    class1.cpp
    Code:
    #include "class1.h"
    
    
      Class1::Class1() {
        a_ = 0;
      }
    
    
    
      int Class1::getA(void) {
        return a_;
      }
    
    
    
      void Class1::setA(int a) {
        a_ = a;
      }
    class2.h

    Code:
      class Class2 {
    
        private:
        Class1 data_[6]; //Clicking error message directs to this line.
        public:
        void setData(int idx, int n);
        int  getData(int idx);
    
      };
    class2.cpp

    Code:
    #include "class1.h"
    #include "class2.h"
    
      void Class2::setData(int idx, int n) {
        data_[idx].setA(n);
      }
    
    
      int Class2::getData(int idx) {
        return data_[idx].getA(idx);
      }
    main.cpp

    Code:
    #include <stdio.h>
    #include "class2.h"
    
    
      int main(int argc, char *argv[]) {
    
        Class2 c2;
        printf("A: %d", c2.getData(2));
        getchar();
        return 0;
      }

    Trying to build this, I get:
    In file included from main.cpp
    `Class1' does not name a type


    To me, that is strange because I was careful in class2.cpp to include class1.h before including class2.h.

    This is just one problem -- as I mentioned, I'm having others (such as multiple declaration errors) but this is what I could come up with for now.

    Thank you both for responding.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by BadNature
    To me, that is strange because I was careful in class2.cpp to include class1.h before including class2.h.
    Your code is fragile: you should be able to include the headers in any order and still have it work. In fact, you should be able to #include "class2.h" without also having to #include "class1.h", if the definition Class2 is desired. Furthermore, you should be able to include a header that includes class1.h, and then also include another header that includes class1.h without a problem.

    Here is how I might write the headers:
    class1.h
    Code:
    #ifndef BADNATURE_CLASS1_H_
    #define BADNATURE_CLASS1_H_
    
    class Class1 {
    public:
        Class1();
        int getA() const;
        void setA(int a);
    private:
        int a_;
    };
    
    #endif
    class2.h
    Code:
    #ifndef BADNATURE_CLASS2_H_
    #define BADNATURE_CLASS2_H_
    
    #include "class1.h"
    
    class Class2 {
    public:
        void setData(int idx, int n);
        int getData(int idx) const;
    private:
        Class1 data_[6];
    };
    
    #endif
    I have taken the liberty of declaring the getA and getData member functions const.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Mar 2011
    Posts
    23
    in your header files add
    Code:
    #pragma once
    this will prevent multiple declarations. A result of multiple declaration is the compilation unit being dropped and data objects declared following the ambiguity are left out and therefore are undefined. Also remove any namespace inclusions from the header and explicitly provide indirection.
    Code:
    using namespace 'namespace';
    Bad use of #ifdef MYCLASS elements can cause silly mistakes.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by pYro
    in your header files add
    Code:
    #pragma once
    this will prevent multiple declarations. A result of multiple declaration is the compilation unit being dropped and data objects declared following the ambiguity are left out and therefore are undefined.
    #pragma once, like all #pragma directives, is implementation specific, i.e., a compiler might not support it, or might support it in a manner different from another compiler. As such, BadNature, I suggest that you use conventional header inclusion guards. You appear to have used such a guard in your first example in this thread, but note that names that begin with an underscore followed by an uppercase letter, or that contain consecutive underscores, are reserved to the implementation for any use, so __MYCLASS_H__ is a bad choice unless you are writing a compiler or standard library implementation.

    Quote Originally Posted by pYro
    Also remove any namespace inclusions from the header and explicitly provide indirection.
    Code:
    using namespace 'namespace';
    Good suggestion, though this does not appear to be a problem in this case. Note that the term is using directive. I presume that the single quotes 'namespace' are just meta-characters.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. preprocessor file inclusion?
    By dwaugh in forum C Programming
    Replies: 4
    Last Post: 08-22-2008, 09:01 AM
  2. Replies: 4
    Last Post: 06-04-2007, 05:37 PM
  3. Why the hell haven't I used WinAmp before?
    By cboard_member in forum A Brief History of Cprogramming.com
    Replies: 20
    Last Post: 08-22-2006, 02:25 AM
  4. Header inclusion causing errors
    By cjschw in forum C++ Programming
    Replies: 12
    Last Post: 08-11-2004, 03:48 PM