Class definition

Defining a class

Classes are defined similarly to structures. A class is defined by writing the keyword class, followed by the name of the class and then braces {} ended by a semicolon ;.

class Window { };

Members categories

Methods and member variables can be defined under one of the following categories: public, private and protected. Do you remember when I told you that it was not possible to directly access the member variables from an object? That is not entirely true. It is technically possible to access a member variable directly from an object if the member has been defined as public. It is however an OOP rule that member variables should (almost) never be defined as public. In some rare cases only, it can be useful to do it, but in general, we should avoid doing that if we do no want to be (negatively) judged by the other programmers.

Encapsulation

In OOP, there is a concept called encapsulation which consists of hiding, from the users, how a class works and simply provide them with an interface (methods), so they can use it without having to understand how the class works internally. Since we do no know how a class somebody else coded works (Unless we read the code of the class, which may be huge and complex), directly accessing the member variables of a class object may make it work wrongly as we do not know exactly how the methods of the class use them.

Let us say there is a class, from a library, named Window, that is used to create and manage a window. It might possess a method, which header is void resize(unsigned sX, unsigned sY), used to change the dimensions of the window. Do we need to know, in order to use it, how the method has been coded? No. All we need to know is what it does and what the arguments represent. If the member variables representing the dimensions of the window were public, maybe the users would want to directly change their values instead of calling methods. However, those users do not know how the class works. For example, maybe the class needs to verify that the dimensions are correct (Not negative or too big), before resizing the window and maybe the class needs to redraw the content of the window when it is resized (Which is done inside the method resize). Basically, encapsulation allows us to use classes, which we do not know how they work, without doing something stupid.

Defining the members under categories

Now, what are the differences between the categories? A public member can be accessed anywhere: From inside (Through its methods) and outside (From objects of that class) the class. A private member can only be accessed from the methods of the class. Finally, a protected member can only be accessed from the methods of the class or from the methods of a class that inherits from that class. To specify the category of a member, we simply need to put, inside the braces {} of the class definition, the name of the category followed by a colon :. Then, all the members defined/declared after it will be of that category.

Note that the members of an object of a class are accessed the same way as the members of an object of a structure are. A reminder: We write the name of the object, then a dot followed by the name of the member we want to access.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <string> class Window { public: // Member of type 'std::string' named '_title', defined as public. std::string _title; protected: // Members of type 'unsigned', defined as protected. unsigned _width, _height; private: // Members of type 'unsigned', defined as private. unsigned _posX, _posY; }; int main() { Window win; // Defines an object of type Window. win._title = "Program name"; // It works. The member is public. win._width = 800; // Error: The member is protected. win._posX = 100; // Error: The member is private. }

The member _title as been defined as public only for the example. As said before, we should normally not declare member variables as public.

Note that, by default, members of a class are private:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A { int memb; }; int main() { A a; a. memb = 47; // Error: The member 'memb' is private. return 0; }

Where to define classes

We usually create files for each class (One header file and one source file). We put the class definition inside the header file and we write the member variable definitions and method declarations inside it. The methods are then defined inside the source file.

Note that it is possible to define the methods inside the class definition if the class is defined in a source file (Like in the example above).

Window.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef WINDOW_HPP #define WINDOW_HPP #include <string> class Window { public: protected: private: std::string _title; unsigned int _width, _height; unsigned _posX, _posY; }; #endif

The source file is empty, for now, because we do not have methods to define yet.

Window.cpp

1
#include "Window.hpp"
1
2
3
4
5
6
7
8
#include "Window.hpp" int main() { Window win; // Defines an object of type Window. return 0; }

Pointers to objects of classes

Like with pointers to objects of structures, the elements of objects of classes are accessed, through pointers, using -> instead of a dot.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream> class Time { public: int _hours; int _minutes; int _seconds; }; int main() { Time time; time._hours = 13; Time* ptr = &time; ptr->_minutes = 41; ptr->_seconds = 0; std::cout << ptr->_hours << " " << ptr->_minutes << " " << ptr->_seconds << "\n"; return 0; }

Classes with object members

Classes can have member variables that are objects.

1
2
3
4
5
6
7
8
9
10
class A { public: int _member; }; class B { public: A _a; };

However, a class can not have members of its type:

1
2
3
4
5
class A { public: A _a; // Error. };

The reason is that it would cause an infinite loop. The class A would have a member _a which would have a member _a which would have a member _a which would have a member _a...

A class can, however, possess a pointer of the class type:

1
2
3
4
5
class A { public: A *_a; // It works. };

Naming convention

In this course, classes are named in PascalCase. Member variables are named in camelCase, prefixed by an underscore _.