Methods

Declaring a method

First of all, we need to declare the methods inside the class definition. It is done the same way as with functions.

Character.hpp

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef CHARACTER_HPP #define CHARACTER_HPP #include <iostream> class Character { public: void presentHimself(); }; #endif

The method presentHimself has been declared as public. If it has been declared as private or protected, it could not be called from outside of the methods of the class (Only the methods of the class could use it).

Defining a method

Once the method is declared in the class definition, we must define it in the source file. It works the same way as with functions, except that we must prefix the name of the method with the name of the class, followed by two colons :: (The method is part of the namespace of the class), to specify it belongs to the class, since it is defined outside of it.

Character.cpp

1
2
3
4
5
6
7
#include "Character.hpp" // Definition of the method presentHimself from the class Character. void Character::presentHimself() { std::cout << "Hello, my name is Samantha." << std::endl; }

Calling a method

As we saw before, to call a method, we write the name of the object to call it from, followed by a comma and then, the name of the method, the arguments (If there are), between parentheses () and a semicolon ;.

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "Character.hpp" int main() { // Defines an object of type Character. Character character; // Calls the method 'presentHimself' from the object 'character'. character.presentHimself(); /* "Hello, my name is Samantha." is printed into the console. */ return 0; }

Accessing the member variables with the methods

We can directly access the member variables of a class, even if they are private of protected, from its methods. When a method that accesses the member variables of a class is called, the member variables of the object it is called from are used.

Character.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef CHARACTER_HPP #define CHARACTER_HPP #include <iostream> class Character { public: void setName(const std::string & name); void presentHimself(); private: std::string _name; }; #endif

Character.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Character.hpp" /* When that method is called, the member '_name' of the object the method is called from, is assigned with the string given as argument. */ void Character::setName(const std::string & name) { _name = name; } void Character::presentHimself() { std::cout << "Hello, my name is " << _name << '.' << std::endl; }

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "Character.hpp" int main() { Character character; // Uses a method to set the value of the member '_name' of the object 'character'. character.setName("Jim"); // Uses a method to display the value of the member '_name' of the object 'character'. character.presentHimself(); /* "Hello, my name is Jim." is printed in the console. */ return 0; }

Setters and getters

A method used to set the value of a member variable is called a setter. The method setName from above is a setter. Setters are often named with the prefix set, followed by the name of the variable in PascalCase, without the underscore _.

A method used to retrieve the value, the address or a reference (Constant or not) to a variable is called a getter. Getters are often named the same way as setters, but with the prefix get instead. Sometimes, they are named exactly like the member variable, but without the underscore _.

Note that returning non-constant references or pointers to member variables is not against the principles of encapsulation, but we should do so only when the member variables may be changed directly without potentially causing problems to the inner working of the class.

Character.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef CHARACTER_HPP #define CHARACTER_HPP #include <iostream> class Character { public: void setName(const std::string & name); const std::string & getName(); void presentHimself(); private: std::string _name; }; #endif

Character.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "Character.hpp" // This method is a setter. void Character::setName(const std::string & name) { _name = name; } /* Returns a constant reference to the member '_name' of the object it is called from. This method is a getter. */ const std::string & Character::getName() { return _name; } void Character::presentHimself() { std::cout << "Hello, my name is " << _name << '.' << std::endl; }

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "Character.hpp" int main() { Character character; character.setName("Jim"); // Retrieves the value of the member '_name' of the object 'character'. std::string charName = character.getName(); std::cout << "We retrieved the name of the character. By the way, it is " << charName << '.' << std::endl; /* "We retrieved the name of the character. By the way, it is Jim." is written to the console. */ return 0; }

Constant methods

Methods defined as constant can not modify the value of the member variables of the object it is called from. Constant objects, constant references and pointers of constant objects can only call constant methods. For that reason, it is really important to define the methods as constant when they does not modify the value of the members of the class. Note that constant methods can not call non-constant methods of the class and can not give non-constant references or pointers of the member variables to a function or method call.

Let us have a look a the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Character.hpp" int main() { Character character; character.setName("Jim"); // Defines a pointer to a constant object of type 'Character'. const Character * ptr = &character; ptr->presentHimself(); // Error: The method presentHimself is not constant. return 0; }

To resolve that, let us define and declare the methods getName and presentHimself as constant since they do not modify the member variables of the class.

Define methods as constant

To define a method as constant, all we have to do is add the keyword const after its parentheses in its declaration and definition.

Character.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef CHARACTER_HPP #define CHARACTER_HPP #include <iostream> class Character { public: void setName(const std::string & name); const std::string & getName() const; void presentHimself() const; private: std::string _name; }; #endif

Character.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "Character.hpp" void Character::setName(const std::string & name) { _name = name; } const std::string & Character::getName() const { return _name; } const std::string & Character::presentHimself() const { std::cout << "Hello, my name is " << _name << '.' << std::endl; }

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "Character.hpp" int main() { Character character; character.setName("Jim"); const Character * ptr = &character; ptr->presentHimself(); // Now it works. return 0; }

Protected and private methods

Protected and private methods are meant to be used internally only, by the methods of the class, since they can not be called from the outside.

Character.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef CHARACTER_HPP #define CHARACTER_HPP #include <iostream> class Character { public: void setName(const std::string & name); const std::string & getName() const; void presentHimself() const; private: void addTitle(); std::string _name; }; #endif

Character.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "Character.hpp" void Character::setName(const std::string & name) { _name = name; addTitle(); } const std::string & Character::getName() const { return _name; } const std::string & Character::presentHimself() const { std::cout << "Hello, my name is " << _name << '.' << std::endl; } void Character::addTitle() { std::string title = "Sir "; _name = title + _name; }

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "Character.hpp" int main() { Character character; character.setName("Jim"); character.presentHimself(); /* "Hello, my name is Sir Jim." is printed in the console. */ /* The following line of code would cause a compilation error, because the method 'addTitle' is private: character.addTitle(); */ return 0; }

The method addTitle is used by the class, internally, to automatically add a title to the name of the character when we set it. The line of code below (If not located inside a method of the class Character) would cause a compilation error, since the method is private:

character.addTitle();

Which is a good thing, because it would have the effect to add the title to the name of the character, a second time. If the name of the character was set to "Luke", then the content of the member _name would become "Sir Sir Luke", which does not make much sense.

The method setName from above is an example of encapsulation. By making the member _name private, the users are forced to use the method setName in order to change the name of the character, and that way, we are sure the name of the character always contains the title "Sir ".

Defining methods inside the class definition

Again, it is possible to define the methods inside the definition of the class, if it is inside a source file. The reasons we can not define methods inside a header file are the same as with functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream> class MyClass { public: void printHello() const { std::cout << "Hello!" << std::endl; } }; int main() { MyClass myClass; myClass.printHello(); return 0; }

Default argument values

Like with functions, we can specify default values for the arguments of methods.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream> class Class { public: void method(int arg=78) { std::cout << arg << std::endl; } }; int main() { Class object; object.method(); object.method(542); object.method(31); return 0; }

Note on structures

In C++, structures can be used the same way as classes. The only real difference is that the members of a structure are, by default, public.

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
#include <iostream> struct A { void method() { std::cout << member << std::endl; } int member; private: int member2; }; int main() { A a; a.member = 60; // Error: //a.member2 = 23; a.method(); return 0; }

Naming convention

In this course, methods are named in camelCase.