473,404 Members | 2,195 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,404 software developers and data experts.

Weird outside class function definition in C++?

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

Expand|Select|Wrap|Line Numbers
  1. class List {
  2.     int x;
  3.     public:
  4.     void foo();
  5. }
  6.  
  7. List::foo ()
  8. {
  9.     x = 0;
  10. }
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.
May 3 '07 #1
26 12568
Ganon11
3,652 Expert 2GB
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.
May 3 '07 #2
AdrianH
1,251 Expert 1GB
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
May 3 '07 #3
Sebouh
78
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?
May 3 '07 #4
AdrianH
1,251 Expert 1GB
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:

Expand|Select|Wrap|Line Numbers
  1. inline void fn()
  2. {
  3.   // do something
  4. }
or this:

Expand|Select|Wrap|Line Numbers
  1. class A
  2. {
  3.   public:
  4.     A()
  5.     {
  6.       // do something
  7.     }
  8. };
or even this:

Expand|Select|Wrap|Line Numbers
  1. class A
  2. {
  3.   public:
  4.     A();
  5. };
  6.  
  7. inline A::A()
  8. {
  9.   // do something
  10. }
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
May 3 '07 #5
Sebouh
78
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.
May 4 '07 #6
AdrianH
1,251 Expert 1GB
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
May 4 '07 #7
Sebouh
78
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.
May 7 '07 #8
DV6
2
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!
May 7 '07 #9
AdrianH
1,251 Expert 1GB
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
May 8 '07 #10
AdrianH
1,251 Expert 1GB
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
May 8 '07 #11
Sebouh
78
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. :)
May 8 '07 #12
AdrianH
1,251 Expert 1GB
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
May 8 '07 #13
Sebouh
78
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.
May 8 '07 #14
AdrianH
1,251 Expert 1GB
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.
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.
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
May 8 '07 #15
Sebouh
78
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
This is exactly what i want to know. Why is this the case? We just agreed inlining doesn't have anything to do with multiple defs.
May 8 '07 #16
AdrianH
1,251 Expert 1GB
This is exactly what i want to know. Why is this the case? We just agreed inlining doesn't have anything to do with multiple defs.
Did we? Ok, according to the link you provided, the optimiser is what does this and can basically do an insertion of the code into the function, something like a macro. Yes, each caller may has its own instance, but it is not the same as having multiple symbols with the same name pointing at different locations.

However, when the compiler makes inline functions, it will either (roughly) embed a copy of the code in to were it is used, thus not having a single symbol apparently pointing at many locations problem, or have a well defined function which is ok to have listed multiple times, so long as it is the same code. The multiple functions instance will then be collapsed in to one instance by the linker.

Does this make sense?


Adrian
May 8 '07 #17
Sebouh
78
Did we? Ok, according to the link you provided, the optimiser is what does this and can basically do an insertion of the code into the function, something like a macro. Yes, each caller may has its own instance, but it is not the same as having multiple symbols with the same name pointing at different locations.

However, when the compiler makes inline functions, it will either (roughly) embed a copy of the code in to were it is used, thus not having a single symbol apparently pointing at many locations problem, or have a well defined function which is ok to have listed multiple times, so long as it is the same code. The multiple functions instance will then be collapsed in to one instance by the linker.

Does this make sense?


Adrian
ok, so this brings me to the question, when is a function not well defined? Do you mean if i put a single, non-inline function in a header file and use this hearder in different sources?
May 8 '07 #18
AdrianH
1,251 Expert 1GB
ok, so this brings me to the question, when is a function not well defined?
In the context that I was speaking, well defined means that in the object file, there is a bunch of bytes representing the code that has entry point(s) and exit point(s).
Do you mean if i put a single, non-inline function in a header file and use this hearder in different sources?
It appears that sentance is a fragment, like you trailed off in thought. ;)


Adrian
May 8 '07 #19
Sebouh
78
In the context that I was speaking, well defined means that in the object file, there is a bunch of bytes representing the code that has entry point(s) and exit point(s).

It appears that sentance is a fragment, like you trailed off in thought. ;)


Adrian
Yup. I tried this and it gave me an already defined error. But when i put inline infront of it, it worked.
Not tryin' be a pain in the ass, but could you tell me why exactly inline made that difference? I mean is putting inline infront of the function tells it this is a "well defined" function?
And another thing. Won't making things inline (automatic or manual) replace every function call with actual body code, thus causing code bloat?
May 8 '07 #20
AdrianH
1,251 Expert 1GB
Yup. I tried this and it gave me an already defined error.
What are you refering to with the word 'this'?
But when i put inline infront of it, it worked.
Not tryin' be a pain in the ass, but could you tell me why exactly inline made that difference? I mean is putting inline infront of the function tells it this is a "well defined" function?
No, no, no. Forget the well defined function bit. Assume that if you make an inline function, there are copies of the code for the function as if you just put the code in the function right where you place the call. There is no symbol for that function, it is just a copy of the body of the function. So therefore, you do not get a redefinition error.

If you do not have the function inline, but still declare the body in the header, every object file will have a copy of the function with a symbol pointing to it. This creates a redefinition conflict as there is many symbols with the same name pointing at different locations.

Tell me if you understand that before I go on.
And another thing. Won't making things inline (automatic or manual) replace every function call with actual body code, thus causing code bloat?
I will not get into this yet till I know you understand what I just previously said. I think the main problem is that I am giving you too much info too fast.


Adrian
May 8 '07 #21
Sebouh
78
What i tried was defining a non-inline function in a header file and including it in two source files that use it. So it gave me redefinition error. (What if only 1 source used it but the other did include it, there will still be a problem right? Cause whatever is in the header is just pasted in the source, used or not).

Ok, so as i understand it, an inline function will never be included in a compiled object file. What will happen is that it's body will be placed anywhere it is called during compilation. So when linking two or more of the sources using this function, there won't be a problem with redefinition since the function is not there, "traces" of it is there (traces meaning its body).

I am right, right? I feel i get it now. But other then continuing with my question about bloating, can you tell me if this occurs with C too? If so, then won't the only solution be to define functions in separate source files and not in headers? (I'm guessing this is how library files are done).:)

P.S. I've got several questions there, sorry for that. I feel like i should get them out of my system ASAP.
May 9 '07 #22
Expand|Select|Wrap|Line Numbers
  1. class List {
  2.     int x;
  3.     public:
  4.     void foo();
  5. }
  6.  
  7. List::foo ()
  8. {
  9.     x = 0;
  10. }
hey! you have just declared the member function "foo()"inside the class but yet to say what it means that is what you have done outside the class declaration .. which is done with the class name ie;list::foo()..
May 9 '07 #23
AdrianH
1,251 Expert 1GB
What i tried was defining a non-inline function in a header file and including it in two source files that use it. So it gave me redefinition error.
Yes, that’s right.
(What if only 1 source used it but the other did include it, there will still be a problem right? Cause whatever is in the header is just pasted in the source, used or not).
Yes, there would be a problem. This is because each source file, when compiled to an object file, will have in the object file an exported symbol that is pointing at a function body. When both object files are linked together, a conflict arises as there are two exported symbols with the same name pointing at different function bodies.
Ok, so as i understand it, an inline function will never be included in a compiled object file. What will happen is that it's body will be placed anywhere it is called during compilation. So when linking two or more of the sources using this function, there won't be a problem with redefinition since the function is not there, "traces" of it is there (traces meaning its body).
Yes, no symbol for the function will be in the object files, just the function bodies.
I am right, right? I feel i get it now. But other then continuing with my question about bloating, can you tell me if this occurs with C too? If so, then won't the only solution be to define functions in separate source files and not in headers? (I'm guessing this is how library files are done).:)
ANSI C does not have a standard for inlining, though there are compiler extensions.

Bloating can occur in C++ builds, but the compiler and the programmer interact to try and minimise this using compiler switches and how the code is written (using inline functions and such).

Now, I want to tell you that though the compiler may inline a function you request, it has the option not to. This can happen if it deems that doing so would bloat the code too much or some other reason (there are many, take a look at the link you provided for more information).

However, even if it does not inline, it will not cause an error if two different source files use it. How it does it is not important, just know that it can do it.
P.S. I've got several questions there, sorry for that. I feel like i should get them out of my system ASAP.
That’s fine, we are here to help.


Adrian
May 9 '07 #24
AdrianH
1,251 Expert 1GB
Expand|Select|Wrap|Line Numbers
  1. class List {
  2.     int x;
  3.     public:
  4.     void foo();
  5. }
  6.  
  7. List::foo ()
  8. {
  9.     x = 0;
  10. }
hey! you have just declared the member function "foo()"inside the class but yet to say what it means that is what you have done outside the class declaration .. which is done with the class name ie;list::foo()..
Hey! ;)

If this is done all in the header file, it will cause an error. If you wish to inline without putting it in the class body, use the inline keyword, either at the function declaration and/or at its definition.

Using the inline keyword only at the definiton which is in the source ahead of its use by the class functions will result in it being inlined there, in the source after it was defined.


Adrian
May 9 '07 #25
Sebouh
78
Alright then. Thanks for helping me solve this puzzle. You've been great!
May 9 '07 #26
AdrianH
1,251 Expert 1GB
Alright then. Thanks for helping me solve this puzzle. You've been great!
Well I'm glad that I was able to help you understand.


Adrian
May 10 '07 #27

Sign in to post your reply or Sign up for a free account.

Similar topics

4
by: oliver.lin | last post by:
In my simple test code, I tried to define my constructor outside of the class declaration headr file. The header file: file_handler.h ============================================================...
8
by: Michel Rouzic | last post by:
I'm sure that it's a dumb problem where i surely did something dumb, but, I got a problem, I got a variable that we'll call var1. in the main() function, this variable var1 (of type unsigned) of a...
2
by: Sai Kit Tong | last post by:
I try to utilize an old native code class library for my managed C++ application, and experience a weird problem. I used IJW approach and included the header file for my native class definition. I...
0
by: Zwyatt | last post by:
having a really weird little bug w/ time_t...check it out: I have the following code (simplified here): #include <time.h> class A { public: char *aString; int aNum;
5
by: Felix I. Wyss | last post by:
Good Afternoon, I recently noticed that some very simple methods of a template declared and used in a DLL library get inlined when used by the DLL itself, but not by other DLLs and EXEs. After...
3
by: Hans De Schrijver | last post by:
I have an assembly with 2 projects. The first project (CLSLibrary) is a Class Library that contains public class User. The second project (CLSTester) is an ASP.NET Web Application that contains a...
10
by: Charles Law | last post by:
For some reason, when I click the X to close my MDI parent form, the action appears to be re-directed to one of the MDI child forms, and the parent remains open. I am then unable to close the...
1
by: ypjofficial | last post by:
Hi all, what's difference does it make when we define the member function inside and outside a class? I am using vc7. when i define the member functions outside a class with the scope...
11
by: utab | last post by:
Dear all, in a class definition class X{ private: static map< string , map<string, int word_map; static void initialize(); };
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.