Structs and Classes
Contents
2.1. Structs and Classes#
In C/C++, to help with data organization, we group together multiple data members of different data types in a struct
. For example, consider the following student
structure:
Code
#include <iostream> using namespace std;
// struct definition struct Student { string name; int ID; };
int main(void) { struct Student x, y; x.name = "Kenya"; x.ID = 8012; y.name = "Cindy"; x.ID = 2023; cout << "X, Name: " << x.name << endl << "ID: " << x.ID << endl; return 0; }
In this structure, we have grouped together a string and an integer. The struct definition, which is lines 5-8, does not involve any memory allocation. When we create an instance of the struct Student
, only then a memory space is reserved for that instance. In line 11, multiple instances of the student structure x
and y
were created, and each one stores different values.
To access data members of a structure, we use the dot operator (.
) on the instance. For example, to access the name
data member of the x
instance, we write x.name
.
Problem! In line 15, when we printed the name and ID of Student x
, we had to access each data member to print them. If there were 10 data members, we would have to access each data member to print them. Unfortunately, that’s a lot of code to write.
Solution 1. We can create a function and name it print
that takes in struct Student
to help us print all data members of struct. This will make our code more modular, especially if we want to print the data members of multiple struct Student
.
Solution 2. Instead of having the print
function separate from Student
struct, we can associate it with Student
and keep it with the other data members of Student
. To do so, we need to bundle the data members and the print
function in a definition of a Student
“class.”
2.1.1. What is a class?#
A class is an expansion to structures in C/C++. It allows us to group data members and functions in a single unit.
A class is a user-defined data type. Creating an instance of a class is called instantiation and the instance is called an object. The program will not allocate memory when the class is defined. Memory will be allocated for each object. You can think of a class as a template/blueprint for creating objects, and only instances of the class or objects will be allocated in the memory.
2.1.2. Defining a class#
To define a class, we use the class
keyword followed by the class name. For example, the following code defines a class Student
with two data members name
and ID
. We also define a function print
that prints the data members of the class.
To keep our code clean and organized, we store the class definition, which includes data members and function prototypes, in a header file (e.g., Student.h).
Code in Student.h
#include <string>
using namespace std;
class Student {
string name;
int ID;
void print();
};
2.1.3. Access Control#
Problem! Members in a class are private by default. This means that the name
, ID
and print
cannot be accessed outside the class, for example, in the main function.
To control access to the members of a class, we can use access specifiers/modifiers. The common two are private
and public
. These access modifiers allow us to dictate which members:
can only be used within a class –
private
, andcan be used inside and outside the class –
public
.
For example, we will edit the class definition in Student.h
to have name
and ID
as private members and print
as a public member. name
and ID
can only be accessed within the class, while print
can be accessed outside the class.
Code in Student.h
#include <string>
using namespace std;
class Student {
private:
string name;
int ID;
public:
void print();
};
To understand further how access specifiers work, we need to create instances of the class and access the members. However, we cannot yet create instances of the class because we have not implemented the function members of Student
.
2.1.4. Implementing functions in a class#
The implementation of the functions in Student
(i.e., the actual code of the print
function) goes into a source file (e.g., Student.cpp). This structure helps with separate compilation and makes large programs easier to manage and debug.
In a source file named Student.cpp
, we will implement the function member of the class Student
. The function print
will print the data members of the class.
Code in Student.cpp
1#include <iostream>
2#include "Student.h"
3using namespace std;
4
5void Student::print() {
6 cout << "Name: " << name << endl << "ID: " << ID << endl;
7}
Lines 1 and 3. We include the iostream
library and write using namespace std;
to use cout
in print
.
Line 2. We include the header file Student.h
to be able to access the class Student
.
Line 5. We define the function print
that prints the data members of the class. Since print
is being implemented outside of the class definition, we need to specify in Student.cpp
in the function header that print
is part of Student
class. To do so, we append to the function name the class name Student
and use the scope resolution operator ::
, i.e., Student::print
.
2.1.5. Creating instances of a class#
We will write a main
function where we create an instance of the Student
class. We will put the main
function in another file named main.cpp
. In main.cpp
, we need to include Student.h
header file to be able to create an instance of Student
class. In Fig. 2.1:
Line 6. We create an instance of the class Student
named x
. This requires only the name of the class followed by the name of the object Student x
. In the memory, a memory space for object x
is created. That space stores two data members: name
and ID
. Since name
and ID
are uninitialized, they will have garbage values denoted by ?
.
Line 7 [Erroneous]. To initialize the value of name
, we attempt to access the data member name
of the object x
using the dot operator. However, we cannot access name
because it is a private member of Student
class.
Line 8. We call the print
function on the instance x
. This is allowed since print
is a public
function of Student
.
**Problem!**However, the outout of the program is undefined because the data members name
and ID
are uninitialized.

Fig. 2.1 Object x
of class Student
with uninitialized data members name
and ID
. Data members are private and cannot be accessed outside the class.#
Output is undefined
Name: hmvjl ID: -87569870
Solution 1 Have the data members name
and ID
public to be able to access them and initialize them in the main
function.
Solution 2 Have public functions that allow you to initialize or “set” the values of name
and ID
and other functions to allow you to read or know or “get” the values of name
and ID
. These functions will be named getters and setters as we discuss in the next section. All this while keeping name
and ID
private.
2.1.6. Getter and Setter functions#
To help gain access to the private members of name
and ID
, we can create getter and setter functions. Getter functions are used to access/return the value of a private member, while setter functions are used to set the value of a private member.
In the following example, we will create getter and setter functions for only the name
data member of the Student
class, we will discuss the ID
in the next section.
As shown below in Student.h
file in lines 11 and 12, we add the function declarations for getName
and setName
functions to the Student
class.
Code in Student.h
1#include <string>
2using namespace std;
3
4class Student {
5 private:
6 string name;
7 int ID;
8
9 public:
10 void print();
11 void setName(string name);
12 string getName();
13};
In Student.cpp
file, in lines 9 to 15, we add the function implementations for getName
and setName
functions.
getName
: The getter forname
will return the value ofname
and received nothing as an input.setName
: The setter forname
will receive a string as an input and assign it toname
.
Code in Student.cpp
1#include <iostream>
2#include "Student.h"
3using namespace std;
4
5void Student::print() {
6 cout << "Name: " << name << endl << "ID: " << ID << endl;
7}
8
9void Student::setName(string n) {
10 name = n;
11}
12
13string Student::getName() {
14 return name;
15}
Below in main.cpp
file in line 8, we invoke the setName
function on object x
, and pass "Cindy"
to the function. This calls the setName()
which is capable of accessing name
member of x
and set it to "Cindy"
.
Therefore, in line 9 in main.cpp, when we invoke the getName
function on object x
, we return the value of name
stored in object x
. Then, we print it to the user as "Cindy"
.
In line 11, we are still invoking print()
on x
while it has an uninitialized ID
. The output will be Name: Cindy
and ID: <undefined>
.
Code in main.cpp
1#include <iostream>
2#include "Student.h"
3using namespace std;
4
5int main(void) {
6 Student x;
7
8 x.setName("Cindy");
9 cout << x.getName() << endl;
10
11 x.print();
12 return 0;
13}
Output (ID is undefined)
Cindy Name: Cindy ID: -86764
getter cannot be used to modify
Getters, like getName
, return the value of a private member, but they cannot be used to modify the value of the private member. For example, we cannot write x.getName() = "Cindy"
to change the value of name
in object x
. This is because getName
returns a copy of the value of name
, which cannot be assigned to another value. getName
does not return a reference to name
.
2.1.7. Summary#
In this section, we have learned about classes in C++. We have seen how to
define a class,
create instances of a class,
access the members of a class,
control access to the members of a class using access specifiers/modifiers, i.e.
private
andpublic
,implement functions in a class,
create getter and setter functions to access private members of a class.
In the next section, we will learn about how can we set private members of a class using constructors at the time of instantiation without need for setter functions.