Thread: separating files for classes and thier implemenation.

  1. #1
    UK2
    Join Date
    Sep 2003
    Posts
    112

    separating files for classes and thier implemenation.

    Hello,

    I have a class that I have written. But have a problem with a compile error. Underfined reference to 'Mammal::GetAge() const'

    I have put my class into a seperate file called Mammal.hpp.
    The implementation is called Mammal.cpp.
    I have another file for testing the application called main.cpp

    I have included the Mammal.hpp header in my Mammal.cpp file.

    I am wondering if this is the correct way to do this?

    Many thanks,

    Mammal.hpp - file
    Code:
    #include <iostream>
    
    class Mammal
    {
        public:
            Mammal():itsAge(10){ std::cout << "Mammal constructor" << std::endl; }
            virtual ~Mammal(){ std::cout << "Mammal distructor" << std::endl; }
    
            void Move() const {std::cout << "Mammal move one step" << std::endl;}
            void Move(int) const {std::cout << "Mammal move a specified number of steps" << std::endl; }
            void GetAge() const;
            void GetWeight() const;
            virtual void Speak() const { std::cout << "Mammal speak" << std::endl; }
    
        protected:
            int itsAge;
            int itsWeight;
    };
    
    void Mammal::GetWeight() const
    {
        std::cout << "Get Weight: " << itsWeight << std::endl;
    }
    Mammal.cpp - file
    Code:
    #include "Mammal.hpp"
    
    void Mammal::GetAge() const
    {
        std::cout << "Age: " << itsAge << std::endl;
    }
    Main.cpp - file
    Code:
    #include "Mammal.hpp"
    
    int main()
    {
        std::cout << "Hello World" << std::endl;
        Mammal myMammal;
        myMammal.Move();
        myMammal.GetAge();
    
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Nov 2006
    Posts
    85
    I had this problem not long ago, I think it was something silly but I can't recall what it was. First try inclusion guards on Mammal.hpp

    Code:
    #ifndef MAMMAL_HPP
    #define MAMMAL_HPP
    #include <iostream>
    
    class Mammal
    {
        public:
            Mammal():itsAge(10){ std::cout << "Mammal constructor" << std::endl; }
            virtual ~Mammal(){ std::cout << "Mammal distructor" << std::endl; }
    
            void Move() const {std::cout << "Mammal move one step" << std::endl;}
            void Move(int) const {std::cout << "Mammal move a specified number of steps" << std::endl; }
            void GetAge() const;
            void GetWeight() const;
            virtual void Speak() const { std::cout << "Mammal speak" << std::endl; }
    
        protected:
            int itsAge;
            int itsWeight;
    };
    #endif
    
    // and put what's below nto Mammal.cpp
    
    void Mammal::GetWeight() const
    {
        std::cout << "Get Weight: " << itsWeight << std::endl;
    }

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    You need to do (minimally)
    g++ Main.cpp Mammal.cpp

    Yes, that's the way to do it.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    UK2
    Join Date
    Sep 2003
    Posts
    112
    Hello,

    Thanks for the reply. I am already using guards on the header files. I didn't show them as I wanted to shorten the code displayed.

    I am using codeblocks GNC complier.

    I have built all the cpp files, and still having a problem.

    Any more ideas?

    Thanks,

  5. #5
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    That is very strange (to me at least). Doesn't work here either (GCC 4.2.3, 64-bit Linux), but with a different error -

    Code:
    cyberfish@cyberfish-desktop:/tmp$ g++ Main.cpp Mammal.cpp
    /tmp/cc7PY0gt.o: In function `Mammal::GetWeight() const':
    Mammal.cpp:(.text+0x1ca): multiple definition of `Mammal::GetWeight() const'
    /tmp/cc0e9ord.o:Main.cpp:(.text+0x204): first defined here
    collect2: ld returned 1 exit status
    I don't see how it's defined in Main.cpp.

    *edit* works if I take out the definition (implementation) of getWeight in the header (or move it to the cpp, as A10 suggests). No idea why. */edit*
    Last edited by cyberfish; 11-06-2008 at 01:38 AM.

  6. #6
    UK2
    Join Date
    Sep 2003
    Posts
    112
    Thanks,

    It worked.

    I moved the GetWeight out of the hpp file and put it into the mammal.cpp file.

    However, I am not sure why? I can only guess that you are not allowed to have any definitions in the header file.

    Thanks,

  7. #7
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    I THINK it's because Mammal.hpp is included by both Main.cpp and Mammal.cpp. That is why GetWeight gets two definitions. Inclusion guard won't help you here because the files are compiled separately.

  8. #8
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    I don't think you can ever have definitions in a header, unless it is a template function.

  9. #9
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    How about inline functions? I thought they have to be defined in the header? (otherwise the compiler won't be able to inline them)

  10. #10
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    I believe inline functions are treated differently by the compiler, and also inlining is purely up to the compiler anyway. Just because you use the 'inline' keyword doesn't necessarily mean it will be inlined.
    Please do not quote me on that, as that information may be inaccurate.(AFAIK basically)

  11. #11
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    True, but the compiler cannot inline function no matter what if the caller and callee are in different files (as in separately compiled).

    That is why, for example, in chess engines, which are mostly CPU-bound, people try to squeeze out the last bit of performance by not using headers at all - and have the main file include all other cpp files. That way the compiler can optimize across the whole program (inlining functions for example).
    Last edited by cyberfish; 11-06-2008 at 02:19 AM.

  12. #12
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    but honestly, is the (fractional) performance gain of in-lining worth it on modern hardware.

  13. #13
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    well, for a typical program running on modern hardware, about 2,000,000 positions can be searched per second. For every position, there needs to be two calls to the "inCheck()" function, which is just a few lines (so the call overhead is comparatively big).

    With my program, going from -O2 to -O3 gives me about 10&#37; increase in performance. -O3 adds things like function inlining and loop unrolling.

    They do everything to get higher performance... many of the best ones have the inner loops written in assembly.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by cyberfish View Post
    True, but the compiler cannot inline function no matter what if the caller and callee are in different files (as in separately compiled).
    Untrue. The compiler, in cooperation with the linker, can do just that.

    That is why, for example, in chess engines, which are mostly CPU-bound, people try to squeeze out the last bit of performance by not using headers at all - and have the main file include all other cpp files. That way the compiler can optimize across the whole program (inlining functions for example).
    That is stupid.
    You should use a proper compiler instead.
    A proper compiler can perform these optimizations even if they are in separate files.
    One such compiler that I know if Visual C++. Microsoft's compiler. There are probably others, too.
    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.

  15. #15
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Untrue. The compiler, in cooperation with the linker, can do just that.
    GCC can't (or am I missing something). In the UNIX world they are done by two different programs entirely (compiling and linking, by gcc and ld).

    It would be truly amazing of the Microsoft compiler if it can do that.

    But is that to say every time a cpp file is changed, the whole project needs to be recompiled? Since that's the only way cross-file inlining can be done?

    If that is the case... then what's the difference between that and including cpp files? (and keeping dummy header files for human reference, or include all headers before all cpp's?)

    I thought one of the main advantages of using headers is that the project can be incrementally compiled.

Popular pages Recent additions subscribe to a feed