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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#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.
![]() |
![]() |
![]() |
The empty
#include
#include
in the codes above are meant to include
iostream and
sys/time.h
Sorry about that!
gcfora
Dear Alex,
Many thanks from my side too for your work here, it is excellent!
I have the following question:
Does run-time performance get worse once we
place the classes we use into separate .cpp (and .h header) files?
I used your Date class above in two ways:
1. included in the file where the main routine is and
2. separated in a new .cpp file along with the appropriate header.
In case 1. , the running time is so much faster than in the case 2. that
I must be doing something wrong!
I post the codes below:
CASE 1.
AllTogether.cpp
------------------------------------------------------------------------------
#include
#include
using namespace std;
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;
};
int main ()
{
struct timeval tvalBefore, tvalAfter;
gettimeofday (&tvalBefore, NULL);
Date day(0,0,0);
for (int i=1; i<=1000000000; i++)
{
Date sun(1, 1, i);
day = sun;
}
cout<<day.GetDay()<<"/";
cout<<day.GetMonth()<<"/";
cout<<day.GetYear()<<"\n";
gettimeofday (&tvalAfter, NULL);
double runtime = (((tvalAfter.tv_sec - tvalBefore.tv_sec)*1000000L
+tvalAfter.tv_usec) - tvalBefore.tv_usec)/1000000.;
cout << "TIME "<<runtime<<" sec"<<endl;
return 0;
}
------------------------------------------------------------------------------
compiled with:
g++ -Wall -O3 AllTogether.cpp
gives as output:
1/1/1000000000
TIME 6.3e-05 sec
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
CASE 2.
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"
using namespace std;
// 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;
}
------------------------------------------------------------------------------
main.cpp
------------------------------------------------------------------------------
#include
#include
#include "Date.h"
using namespace std;
int main ()
{
struct timeval tvalBefore, tvalAfter;
gettimeofday (&tvalBefore, NULL);
Date day(0,0,0);
for (int i=1; i<=1000000000; i++)
{
Date sun(1, 1, i);
day = sun;
}
cout<<day.GetDay()<<"/";
cout<<day.GetMonth()<<"/";
cout<<day.GetYear()<<"\n";
gettimeofday (&tvalAfter, NULL);
double runtime = (((tvalAfter.tv_sec - tvalBefore.tv_sec)*1000000L
+tvalAfter.tv_usec) - tvalBefore.tv_usec)/1000000.;
cout << "TIME "<<runtime<<" sec"<<endl;
return 0;
}
------------------------------------------------------------------------------
now compiled with:
g++ -Wall -O3 Date.cpp main.cpp
gives as output:
1/1/1000000000
TIME 6.05451 sec
What is really going on here?
Many thanks,
gcfora
hmm what about if i want yung a string type? it is the same as int? because i use codeblock IDE hmmm its not working a seperate file if i use string type
+++++main.cpp file++++
#include
#include "Hasith.h"
using namespace std;
int main(){
Hasith has;
return 0;
}
______________________
+++++Hasith.h file++++
#ifndef HASITH_H
#define HASITH_H
class Hasith{
public:
Hasith();
};
#endif
______________________
++++Hasith.cpp file++++
#include "Hasith.h"
#include
using namespace std;
Hasith::Hasith(){
cout<<"i am programming now...!"<bcc32 main.cpp
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
main.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
Error: Unresolved external 'Hasith::Hasith()' referenced from C:\USERS\ADMINISTR
ATOR\DESKTOP\NEW FOLDER\MAIN.OBJ
and, when i am compiling Hasith.cpp
i got like this..
C:\Users\Administrator\Desktop\New folder>bcc32 Hasith.cpp
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
Hasith.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
Error: Unresolved external '_main' referenced from C:\BORLAND\BCC55\LIB\C0X32.OB
J
place anyone tell me what is the problem here..
and what is the correct way to doing this...
and according to the Hasith.h file what are the
#ifndef HASITH_H
#define HASITH_H
#endif
Thank you..
Hello,
I have created a child class and parent class in header files, these are the code:
Child Class:
#ifndef PERRO_H_
#define PERRO_H_
#include "Mamifero.h"
class Perro : public Mamifero {
public:
Perro():raza(COLLEN){}
~Perro();
RAZA getRaza() const {return raza;};
void setRaza(RAZA _raza) {raza = _raza;};
void moverCola() const {cout<<"Cola meneandola..."<<endl;}
void pedirComida() const {cout<<"Pidiendo Comida..."<<endl;}
protected:
RAZA raza;
};
#endif /* PERRO_H_ */
And the parent class:
#ifndef MAMIFERO_H_
using namespace std;
enum RAZA {COLLEN, CALEN , DANDIE, SERTLAN, DOBERMAN, LAB};
class Mamifero {
public:
Mamifero(): age(2), weight(5) {}
~Mamifero(){};
int getAge() const {return age;}
int getWeight() const {return weight;}
void setWeight(int _weight) {weight = _weight;}
void setAge(int _age) {age = _age;}
void hablar() const {cout<<"Sonido Mamimero"<<endl;};
void dormir() const {cout<<"shhh... esta durmiendo"<<endl;};
protected:
int age;
int weight;
};
#endif /* MAMIFERO_H_ */
and this i what i want to get from the main:
#include
#include "Mamifero.h"
#include "Perro.h"
using namespace std;
int main() {
Perro model;
model.hablar();
model.moverCola();
cout<<"Model tiene "<<model.getAge() <<" anhos de edad"<<endl;
return 0;
}
But i do not know what is happening with the enum data type because i recieve
this logs in the console:
..\src\/Mamifero.h:11:6: error: multiple definition of 'enum RAZA'
..\src\/Mamifero.h:11:6: error: previous definition here
..\src\/Mamifero.h:13:7: error: redefinition of 'class Mamifero'
..\src\/Mamifero.h:13:7: error: previous definition of 'class Mamifero'
I can not get the reason why the enum is duplicated or something similar.
Could you please help with this.
Thanks
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!
why don't we just put all the code in the header file?
all what you have written is right as long as the program is running the way you expect
Hi...
Thanks for the tutorial pages, it is magnificent.
I have a problem over here:
mymath.h
mymath.cpp
mymathtest.cpp
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?
You 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:-