Defining member functions outside the class definition
All of the classes that we have written so far have been simple enough that we have been able to implement the functions directly inside the class definition itself. For example, here’s our ubiquitous Date class:
class Date
{
private:
int m_nMonth;
int m_nDay;
int m_nYear;
Date() { } // private default constructor
public:
Date(int nMonth, int nDay, int nYear)
{
SetDate(nMonth, nDay, nYear);
}
void SetDate(int nMonth, int nDay, int nYear)
{
m_nMonth = nMonth;
m_nDay = nDay;
m_nYear = nYear;
}
int GetMonth() { return m_nMonth; }
int GetDay() { return m_nDay; }
int GetYear() { return m_nYear; }
};
However, as classes get longer and more complicated, mixing the definition and the implementation details makes the class harder to manage and work with. Typically, when looking at a class definition (for an already written class), you don’t care how things are implemented — you want to know how to use the class, which involves only it’s definition. In this case, all of the implementation details just get in the way.
Fortunately, C++ provides a way to separate the definition portion of the class from the implementation portion. This is done by defining the class member functions outside of the class definition. To do so, simply define the member functions of the class as if they were normal functions, but prefix the class name to the function using the scope operator (::) (same as for a namespace).
Here is our Date class with the Date constructor and SetDate() function defined outside of the class definition. Note that the prototypes for these functions still exist inside the class definition, but the actual implementation has been moved outside:
class Date
{
private:
int m_nMonth;
int m_nDay;
int m_nYear;
Date() { } // private default constructor
public:
Date(int nMonth, int nDay, int nYear);
void SetDate(int nMonth, int nDay, int nYear);
int GetMonth() { return m_nMonth; }
int GetDay() { return m_nDay; }
int GetYear() { return m_nYear; }
};
// Date constructor
Date::Date(int nMonth, int nDay, int nYear)
{
SetDate(nMonth, nDay, nYear);
}
// Date member function
void Date::SetDate(int nMonth, int nDay, int nYear)
{
m_nMonth = nMonth;
m_nDay = nDay;
m_nYear = nYear;
}
This is pretty straightforward. Because access functions are often only one line, they are typically left in the class definition, even though they could be moved outside.
Here is another example:
class Calc
{
private:
int m_nValue;
public:
Calc() { m_nValue = 0; }
void Add(int nValue) { m_nValue += nValue; }
void Sub(int nValue) { m_nValue -= nValue; }
void Mult(int nValue) { m_nValue *= nValue; }
int GetValue() { return m_nValue; }
};
becomes:
class Calc
{
private:
int m_nValue;
public:
Calc() { m_nValue = 0; }
void Add(int nValue);
void Sub(int nValue);
void Mult(int nValue);
int GetValue() { return m_nValue; }
};
void Calc::Add(int nValue)
{
m_nValue += nValue;
}
void Calc::Sub(int nValue)
{
m_nValue -= nValue;
}
void Calc::Mult(int nValue)
{
m_nValue *= nValue;
}
In this case, we left the default constructor in the class definition because it was so short.
Putting class definitions in a header file
In the lesson on header files, you learned that you can put functions inside header files in order to reuse them in multiple files or even multiple projects. Classes are no different. Class definitions can be put in header files in order to facilitate reuse in multiple files or multiple projects. Traditionally, the class definition is put in a header file of the same name as the class, and the member functions defined outside of the class are put in a .cpp file of the same name as the class. You may sometimes hear the term “one file, one class”, which alludes to the principle of putting classes in their own separate header/code files.
Here’s our Date class again, broken into a .cpp and .h file:
Date.h:
#ifndef DATE_H
#define DATE_H
class Date
{
private:
int m_nMonth;
int m_nDay;
int m_nYear;
Date() { } // private default constructor
public:
Date(int nMonth, int nDay, int nYear);
void SetDate(int nMonth, int nDay, int nYear);
int GetMonth() { return m_nMonth; }
int GetDay() { return m_nDay; }
int GetYear() { return m_nYear; }
};
#endif
Date.cpp:
#include "Date.h"
// Date constructor
Date::Date(int nMonth, int nDay, int nYear)
{
SetDate(nMonth, nDay, nYear);
}
// Date member function
void Date::SetDate(int nMonth, int nDay, int nYear)
{
m_nMonth = nMonth;
m_nDay = nDay;
m_nYear = nYear;
}
Now any other header or code file that wants to use the date class can simply #include "Date.h". Note that Date.cpp also needs to be compiled into any project that uses Date.h so the linker knows how Date is implemented. Don’t forget the header guards on the .h file!
In future lessons, most of our classes will be defined in the .cpp file, with all the functions implemented directly in the class definition. This is just for convenience and to keep the examples short. In real projects, it is much more common for classes to be put in their own code and header files.
8.10 — Const class objects and member functions
|
Index
|
8.8 — Constructors (Part II)
|
8.10 — Const class objects and member functions
Index
8.8 — Constructors (Part II)
“Fortunately, C+ provides a way…”
==> “Fortunately, C++ provides a way…”
:)
[ Fixed! Thanks! -Alex ]
[...] 2007 Prev/Next Posts « 8.7 — The hidden “this” pointer | Home | 8.9 — Class code and header files » Friday, September 7th, 2007 at 9:22 [...]
Hi,
I’m having some trouble with what seems like using class in the class I’m writing.
This is the header file:
#ifndef GUEST_H
#define GUEST_H
using namespace std;
class Guest {
private:
string Name, Addr1, Addr2, Phone;
int Smoking, Pets; //0=none
public:
// default constructor
Guest() ;
// destructor
~Guest() ;
//…other member functions…
};
#endif
The problem is, the compiler doesn’t seem to recognize when a member function tries to use Name. I’ve tried inserting std::string instead of string for the initialization, but that didn’t seem to work.
Thanks
Did you
?
Yes I did. (in the main.cpp file only, right?)
But, there should be nothing preventing my class from using class, right? Don’t need “friend” declarations or anything.
If it helps, I’m using Dev-C++ 4.9.9.2 (the latest version).
You should #include the string header wherever you declared your class declaration. Once you do that, your class should be able to use it just fine. Make sure you’re including “string” and not “string.h”.
Ah, I got it. I added #include <string> to Guest.cpp, and it worked properly. Thx!
P/S Love your site :-)
One of the most important tools in coding.. no matter what programming language it is, you ALWAYS have to import your libraries.
I think thr is another advantage of seperating implementation from defention in header files and cpp files.
Suppose you are writing a Application Programming Interface ( a DLL or .so file) which your clients would be using, you normally give them the header files and the dynamic link libraries. As long as the signature of the methods defined in the interface does not change your client can make use of your diffrent vesions of your API. Also this is a good idea as you dont need to expose your source code to your client exposing all methods available in the API and a users manual on how to use them.
I try to go to the next page in Google Crome browser and I get this message:
Warning: Visiting this site may harm your computer!
The website at http://www.learncpp.com contains elements from the site 61.132.75.71, which appears to host malware – software that can hurt your computer or otherwise operate without your consent. Just visiting a site that contains malware can infect your computer.
For detailed information about the problems with these elements, visit the Google Safe Browsing diagnostic page for 61.132.75.71.
Learn more about how to protect yourself from harmful software online.
I understand that visiting this site may harm my computer.
Its crome’s defense thing. It must be coming from an ad. I know this is a good website.
Yeah, someone used an SQL injection attack to embed an iframe to the IP you list above into the page. I removed it so you should no longer have any trouble. Thanks for letting me know.
[...] 2007 Prev/Next Posts « 8.9 — Class code and header files | Home | 8.11 — Static member variables » Tuesday, September 11th, 2007 at 6:19 [...]
what is the point of constructors? they are a waste of time to me, i just allocate the variables int the class
The point of constructors is to initialize the members of your class when the class object is created.
There is no other way to initialize constant members of a class, for example.
Hi!
It’s a good idea to put classes and other functions in header files but can we put them in a .dll file?If so,can you make a short tutorial of how to make a Dinamic Link Library in VC++ 08??
You can create your own .dll files using Visual Studio, but doing so is pretty complex and beyond the scope of these tutorials.
I just tried writing my own Date class using separate files, but using default parameters for the constructor
. I wasn’t sure if the default parameters should be in the date.h or date.cpp file (or both). With a little t
rial and error, discovered that the default parameters should go in the header file only. Maybe this should b
e mentioned in the tutorial?
By the way – Fantastic tutorial :-)
Thanks for this tutorial but I am having some trouble
I created the date.h like this
#ifndef DATE_H
#define DATE_H
class Date
{
private:
int m_nMonth;
int m_nDay;
int m_nYear;
Date() { } // private default constructor
public:
Date(int nMonth, int nDay, int nYear);
void SetDate(int nMonth, int nDay, int nYear);
int GetMonth();
int GetDay() { return m_nDay; }
int GetYear() { return m_nYear; }
};
#endif
And I created the file date.cpp like this
#include “date.h”
// Date constructor
Date::Date(int nMonth, int nDay, int nYear)
{
m_nMonth=nMonth;
m_nDay=nDay;
m_nYear=nYear;
}
// Date member function
void Date::SetDate(int nMonth, int nDay, int nYear)
{
m_nMonth = nMonth;
m_nDay = nDay;
m_nYear = nYear;
}
int Date::GetMonth()
{
return m_nMonth;
}
and this is what I created for main file
#include
#include “date.h”
using namespace std;
int main()
{
int s, d, f;
cout << “enter the day” <> s;
cout << “enter the month” <>d;
cout << “enter the year” <> f;
Date q(s, d, f);
return q.GetMonth();
}
When I run this on NetBeans on Fedora 11 I get this output
gmake: Warning: File `nbproject/Makefile-variables.mk’ has modification time 1.2e+03 s in the future
/usr/bin/gmake -f nbproject/Makefile-Debug.mk SUBPROJECTS= .build-conf
gmake[1]: Entering directory `/media/disk/c++/netbeans/sample/String’
gmake[1]: Warning: File `nbproject/Makefile-variables.mk’ has modification time 1.2e+03 s in the future
/usr/bin/gmake -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux-x86/string
gmake[2]: Entering directory `/media/disk/c++/netbeans/sample/String’
gmake[2]: Warning: File `nbproject/Makefile-variables.mk’ has modification time 1.2e+03 s in the future
mkdir -p build/Debug/GNU-Linux-x86
rm -f build/Debug/GNU-Linux-x86/main.o.d
g++ -c -g -MMD -MP -MF build/Debug/GNU-Linux-x86/main.o.d -o build/Debug/GNU-Linux-x86/main.o main.cpp
mkdir -p dist/Debug/GNU-Linux-x86
g++ -o dist/Debug/GNU-Linux-x86/string build/Debug/GNU-Linux-x86/main.o
build/Debug/GNU-Linux-x86/main.o: In function `main’:
/media/disk/c++/netbeans/sample/String/main.cpp:13: undefined reference to `Date::Date(int, int, int)’
/media/disk/c++/netbeans/sample/String/main.cpp:14: undefined reference to `Date::GetMonth()’
collect2: ld returned 1 exit status
gmake[2]: *** [dist/Debug/GNU-Linux-x86/string] Error 1
gmake[2]: Leaving directory `/media/disk/c++/netbeans/sample/String’
gmake[1]: *** [.build-conf] Error 2
gmake[1]: Leaving directory `/media/disk/c++/netbeans/sample/String’
gmake: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 726ms)
Can anyone help me?
Thanks
@Alex
im also in a fix whether the member functions should be defined in .h or .cpp, for reusability and less redundancy it should be defined in .h so other .cpp files use it as is?
Flying fish: you are using cout instead of cin…?
Hi…
Thanks for the tutorial pages, it is magnificent.
I have a problem over here:
mymath.h
#ifndef MYMATH_H #define MYMATH_H class mymath { public: mymath(); ~mymath(); int mult(int a, int b); private: }; #endifmymath.cpp
#include "mymath.h" mymath::~mymath() { } mymath::mymath() { } int mymath::mult(int a, int b) { int c; c = a * b; return c; }mymathtest.cpp
#include <iostream.h> #include "mymath.h" void main() { mymath q; int n; n = q.mult(5, 7); cout << "5 x 7 = " << n << endl; }compile result an error messages:
Unresolved external ‘mymath::~mymath()’ referenced from [folder]mymathtest.obj
Unresolved external ‘mymath::mymath()’ referenced from [folder]mymathtest.obj
Unresolved external ‘mymath::mult(int, int)’ referenced from [folder]mymathtest.obj
I work around this problem for hours (not the same code but the same idea), I don’t know where the codes went wrong
and the last trial and error solve the problem, by adding a single line at the bottom of mymath.h, but is it the right way?
#ifndef MYMATH_H #define MYMATH_H class mymath { public: mymath(); ~mymath(); int mult(int a, int b); private: }; #include "mymath.cpp" // Here the new line added #endifYou don’t need to add that last line of code in mymath.h
Just add mymath.cpp to your project (I believe it gets linked in). I managed to get your original code working ok like this. Alex states:-
all what you have written is right as long as the program is running the way you expect
why don’t we just put all the code in the header file?
[...] 8.9 Class code and header files [...]
In the second-to-last paragraph you said :
“simply #include “Date.h”. Note that Date.cpp also needs to be compiled into any project that uses Date.h so the linker knows how Date is implemented. ”
but why we didn’t include the Date.cpp file and the compiler knows where it is ,and compiles it? this confuses me for long time ,(i am a new C++ learner) Thanks Alex!
By the way ,this tutorial is excellent,master piece! I want to work with you! Hah, but now I am a Chinese live in China. I longing US badly!