Weird outside class function definition in C++?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Sebouh
    New Member
    • Feb 2007
    • 77

    Weird outside class function definition in C++?

    Hi guys.
    I'm C++ illiterate, so i find things weird. One example is this.

    Code:
    class List {
        int x;
        public:
        void foo();
    }
    
    List::foo ()
    {
        x = 0;
    }
    Now the first part is in a header file, the second is in another source file.
    What is this exactly? Is the function being defined later on outside the class? So that's possible in C++?
    Thanks.
  • Ganon11
    Recognized Expert Specialist
    • Oct 2006
    • 3651

    #2
    This is something that I'm still a little confused about, too, but I'l try and explain:

    In the .h file (header file), you are declaring your class, along with functions, member variables, etc. In your main program, when you import this .h file, you are telling the program, "Hey, there exists a class called THIS which has all of THESE functions and properties." That way, the main .cpp file can trust that they have been implemented correctly and instantiate THIS objects, etc. At this point, all the main program cares about is that THIS exists - not how it's implemented.

    Now, when you start using THIS objects, the main program needs to look for the implementation. The actual code is included in another .cpp file, so the main program looks in there for the correct function, executes that code, and is happy. The code and definition is seperated (I think!) so that, if your main program only uses 3 out of 100 functions in your THIS class, it doesn't have to load and interpret the other 97 functions because they were in your .h file.

    I also know that, if you ever use templates in your classes, the functions depending on that template must be defined in the same file.

    Comment

    • AdrianH
      Recognized Expert Top Contributor
      • Feb 2007
      • 1251

      #3
      Originally posted by Ganon11
      This is something that I'm still a little confused about, too, but I'l try and explain:

      In the .h file (header file), you are declaring your class, along with functions, member variables, etc. In your main program, when you import this .h file, you are telling the program, "Hey, there exists a class called THIS which has all of THESE functions and properties." That way, the main .cpp file can trust that they have been implemented correctly and instantiate THIS objects, etc. At this point, all the main program cares about is that THIS exists - not how it's implemented.

      Now, when you start using THIS objects, the main program needs to look for the implementation. The actual code is included in another .cpp file, so the main program looks in there for the correct function, executes that code, and is happy. The code and definition is separated (I think!) so that, if your main program only uses 3 out of 100 functions in your THIS class, it doesn't have to load and interpret the other 97 functions because they were in your .h file.

      I also know that, if you ever use templates in your classes, the functions depending on that template must be defined in the same file.
      Ganon is sorta mostly right. ;)

      C++ inherited C's "declare before use" idiom. This means that you must declare the signature of what you are using prior to using it. The header file is to consist of the prototypes (aka declarations) of the functions/variables/classes/structs/enums that are to be used. Where as the source file is to consist of the definitions/bodies of the same (well mostly, I'll get in to that in a moment).

      If you were to have a function's or variable's definition in the header file, this will result in there being multiple code/data instances generated for the body of one declaration every time you include the header file into a source file. That in turn will result in a linking error stating that you have multiple definitions for that function/variable. To the uninitiated, this could be confusing as the error appears to be pointing at the same line, but since it is being included from a difference source file, it is actually a difference instance.

      Classes/structs and enums are slightly different because no code or data is actually generated so no linking problems will occur. However, you can either declare the class/struct or enum in the header file without actually defining it. This can done with "declare be for use" because to the compiler all enums/reference or pointer types have the same respective underlying physical representation, though not the same logical one.

      Sounds weird? Well, not as much as you think. Consider: you want a class/struct or enum to be passed around by pointer or reference but don't want anybody to know what the underlying implementation is or its interface/values. How can you do that? By declaring the class/struct or enum without defining it. In order to use the class/struct or enum, you would have to pass it to a function that does know how to operate on it.

      However, as you probably know, classes/structs and enums are capable of being defined in the header file. This allows the user of the class/struct or enum to use in a more interactive way in their code.

      Now in my second paragraph, I separated the declarations from the definitions using header and source files. This is not always the case. If you define a function as static in you header file (not within a class/struct construct), you are telling the compiler to generate code local to the source file that is including it. This means that there will be as many instances of that function body as are includes to the header file. If this is included 100 times, you will have 100 instances. That could be a lot of code bloat, but is useful under certain circumstances.

      Additionally, under the current implementations of C++, templates definitions must be visible to the code that uses them. This is not required by the standard, but is a workaround as there are no current binary representations of templates in object/library files (object/library files are supposed to be language independent). Code instances are actually not generated until the code is invoked (called) by some other concrete function. If a template function calls another template function, the code instance resulting from that template function call chain is not generated until it is called by a concrete function.

      And now for the reason:

      When you compile a source file, you generate a binary object file. This object consists of all the code generated from the source. By separating the declaration from the definition, the compiler doesn't have to recompile the same code over and over again. It just knows that there are functions/variables around that have a particular signature and name and will assume that during linking, these will be available. If they are not, you will get a linking error saying that the definition is not found for such and such.

      What I have said is mostly true, there are a few things that I have left out and there are probably a couple of errors due to me having a life outside of writing this ;). This is a good start of a book :). If I have confused you, please write back and I will endeavour to make it clearer then mud. :D


      Adrian

      Comment

      • Sebouh
        New Member
        • Feb 2007
        • 77

        #4
        You guys certainly know your stuff.
        I got some of what you said Adrian. But wouldn't the solution to the multiple copying of the same code be using a #ifndef in the header file? If the class is not defined, define it with all it's method definitions. Won't this stop the compiler to paste the same code multiple times?

        Comment

        • AdrianH
          Recognized Expert Top Contributor
          • Feb 2007
          • 1251

          #5
          Originally posted by Sebouh
          You guys certainly know your stuff.
          I got some of what you said Adrian. But wouldn't the solution to the multiple copying of the same code be using a #ifndef in the header file? If the class is not defined, define it with all it's method definitions. Won't this stop the compiler to paste the same code multiple times?
          No, this is because of how the compile passes work.

          1st pass, compile source file to object file
          2nd pass, link all object files
          (there could be potentially other passes intertwined here, such as optimisation)

          What you are referring to stops redefinitions in the 1st pass I described, not in the link pass. So if you have two source files using the same function and it contains the implantation, then you will have an instance of the function in two object files. The linker will not like that and report an error.

          This is true except for when you put in inline functions. Inline functions have the same limitations as template functions. The implementation must be available to the code that is calling it. Thus you can do this:

          Code:
          inline void fn()
          {
            // do something
          }
          or this:

          Code:
          class A
          {
            public:
              A()
              {
                // do something
              }
          };
          or even this:

          Code:
          class A
          {
            public:
              A();
          };
          
          inline A::A()
          {
            // do something
          }
          This is sort of like using static, where each source including the header would have its own copy, except that it is actually folded in to the function that calls it. This is actually only a hint. The compiler can ignore it, but will not generate a link error even if each has an instance of the code in each object file possibly using weak symbols (this is implementation dependent so I will not go any further. Try looking it up for more info).

          Does that answer your question?


          Adrian

          Comment

          • Sebouh
            New Member
            • Feb 2007
            • 77

            #6
            I sort of get what you mean, but since i'm a C++ newbie it's kinda making it hard.
            Can you suggest a tutorial or something that can teach me tricks like these?
            thanks alot.

            Comment

            • AdrianH
              Recognized Expert Top Contributor
              • Feb 2007
              • 1251

              #7
              Originally posted by Sebouh
              I sort of get what you mean, but since i'm a C++ newbie it's kinda making it hard.
              Can you suggest a tutorial or something that can teach me tricks like these?
              thanks alot.
              Sorry, a lot of these come from experience. (inline and template are defined in books but I've yet to find one that states how to use it correctly with the current compilers).

              What exactly did you not understand, and I"ll try and explain it better.


              Adrian

              Comment

              • Sebouh
                New Member
                • Feb 2007
                • 77

                #8
                Originally posted by AdrianH
                Sorry, a lot of these come from experience. (inline and template are defined in books but I've yet to find one that states how to use it correctly with the current compilers).

                What exactly did you not understand, and I"ll try and explain it better.


                Adrian
                Sorry for the late reply, but now i get what you mean. On the frist pass, each source will have the function definition because #ifndef doesn't check other source files. Then when linking there will be two of them...

                One question though. If it's ok for the constructor to be defined inside the class in this situation, is it ok for the destructor too?
                Thanks.

                Comment

                • DV6
                  New Member
                  • May 2007
                  • 2

                  #9
                  Thanks adrainH, i was just looking up why my linker complaind about a constructor defined outside the class when i saw this topic. You really explained a lot to me, however you say there are more things about it and me beeing a non-socializer wants to know as much as possible about programming (especially in C++). Can you tell us what you left out or point me to a good resource explaining more?

                  Thanks!

                  Comment

                  • AdrianH
                    Recognized Expert Top Contributor
                    • Feb 2007
                    • 1251

                    #10
                    Originally posted by Sebouh
                    Sorry for the late reply, but now i get what you mean. On the frist pass, each source will have the function definition because #ifndef doesn't check other source files. Then when linking there will be two of them...

                    One question though. If it's ok for the constructor to be defined inside the class in this situation, is it ok for the destructor too?
                    Thanks.
                    If you define the constructor/destructor or any other member function inside the class, it is like you used the inline keyword. Everything that I said related to inline functions apply.

                    One thing about doing that is that you loose out on information hiding. But sometimes the tradeoffs are worth it. The determination is up to you.


                    Adrian

                    Comment

                    • AdrianH
                      Recognized Expert Top Contributor
                      • Feb 2007
                      • 1251

                      #11
                      Originally posted by DV6
                      Thanks adrainH, i was just looking up why my linker complaind about a constructor defined outside the class when i saw this topic. You really explained a lot to me, however you say there are more things about it and me beeing a non-socializer wants to know as much as possible about programming (especially in C++). Can you tell us what you left out or point me to a good resource explaining more?

                      Thanks!
                      Hmmm, I'm not entirely sure where I acquired all of my knowledge on this. Mostly experience, deduction and University classes I guess. I found that Bruce Eckel's "Thinking in C++" was good, but I'm not sure if it touched upon what I said in this thread.

                      If you have any specific questions, feel free and post them (to a new thread if unrelated to this topic).

                      Good luck


                      Adrian

                      Comment

                      • Sebouh
                        New Member
                        • Feb 2007
                        • 77

                        #12
                        Originally posted by AdrianH
                        If you define the constructor/destructor or any other member function inside the class, it is like you used the inline keyword. Everything that I said related to inline functions apply.

                        One thing about doing that is that you loose out on information hiding. But sometimes the tradeoffs are worth it. The determination is up to you.


                        Adrian
                        OK, I have reread your posts and I used this link for further reference.
                        I have some questions.
                        You said the member functions are automatically inline. So is the constructor and destructor.
                        If i define the function inside the class, i'll get a new def in each source file that uses it. But for classes no code gets generated as you said, so multiple includes for the header containing the class doesn't do harm. Now in this last part, the class members don't get defined twice right? But the destructor and constructor that are defined with the class header, won't they get included miultiple times for each source (like with functions)? Or are these considered to be different than functions? On a side note, what about lets say the copy constructor?

                        If i'm not clear please say so, cause i'm late for class so i wrote as fast as i could. :)

                        Comment

                        • AdrianH
                          Recognized Expert Top Contributor
                          • Feb 2007
                          • 1251

                          #13
                          Originally posted by Sebouh
                          OK, I have reread your posts and I used this link for further reference.
                          I have some questions.
                          You said the member functions are automatically inline. So is the constructor and destructor.
                          If i define the function inside the class, i'll get a new def in each source file that uses it. But for classes no code gets generated as you said, so multiple includes for the header containing the class doesn't do harm. Now in this last part, the class members don't get defined twice right? But the destructor and constructor that are defined with the class header, won't they get included miultiple times for each source (like with functions)? Or are these considered to be different than functions? On a side note, what about lets say the copy constructor?

                          If i'm not clear please say so, cause i'm late for class so i wrote as fast as i could. :)
                          You’re not clear. :) But I think I understand what you are saying.

                          All functions, be they constructors/destructors or regular member functions. They are all subject to inlining, no matter what inlining technique you use.

                          If I haven’t answered you question, try and restate it.


                          Adrian

                          Comment

                          • Sebouh
                            New Member
                            • Feb 2007
                            • 77

                            #14
                            Originally posted by AdrianH
                            You’re not clear. :) But I think I understand what you are saying.

                            All functions, be they constructors/destructors or regular member functions. They are all subject to inlining, no matter what inlining technique you use.

                            If I haven’t answered you question, try and restate it.


                            Adrian
                            Ok let me makes this as clear as possible:
                            - The relation between inlining and multiple definitions of same function at link phase: They have no relation right? inlining will simply replace the function call with the body of this function. It has nothing to do with preventin multiple defs of same func.
                            - Multiple defs of same function: If i am defining functions inside the class (in a header file), then each source (including the header file) will have it's copy. These sources combined will have many of same definition of this function, resulting an error. So as a constructor or destructor defined inside the class, won't there be many of them too, just like with the functions? Leading to an error?

                            I feel like i've asked these already, but i got confused as i reread everything.
                            Thanks.

                            Comment

                            • AdrianH
                              Recognized Expert Top Contributor
                              • Feb 2007
                              • 1251

                              #15
                              Originally posted by Sebouh
                              Ok let me makes this as clear as possible:
                              - The relation between inlining and multiple definitions of same function at link phase: They have no relation right? inlining will simply replace the function call with the body of this function.
                              Not exactly as simple as that, but close enough conceptually to give you the idea.
                              Originally posted by Sebouh
                              It has nothing to do with preventin multiple defs of same func.

                              - Multiple defs of same function: If i am defining functions inside the class (in a header file), then each source (including the header file) will have it's copy.
                              The header file doesn't generate an object file, so it doesn't actually generate a binary copy. But it would be like each source/header has the code to generate the function definition.
                              Originally posted by Sebouh
                              These sources combined will have many of same definition of this function, resulting an error.
                              No. If the functions (including the constructor/destructor) is defined within the class or external to the class using the inline keyword, you will not get an error.


                              Adrian

                              Comment

                              Working...