Search

8.9 — Class code and header files

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:

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:

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:

becomes:

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:

Date.cpp:

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)

28 comments to 8.9 — Class code and header files

  • gcfora

    The empty
    #include
    #include

    in the codes above are meant to include

    iostream and
    sys/time.h

    Sorry about that!

    gcfora

  • 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

  • lloricode

    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

  • hasith

    +++++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..

  • Marvin

    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!

  • Gio

    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

  • hakaye azure

    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:
    };	
    #endif
    

    mymath.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
    #endif
    
    • Gammerz

      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:-

      Note that Date.cpp also needs to be compiled into any project that uses Date.h so the linker knows how Date is implemented.

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">