Home | Projects | Notes > C++ Programming > Classes & Objects
Model real-world entities
Blueprint from which objects are created
A user-defined data-type
Has attributes (data; instance variables)
Has methods (functions)
Can hide data and methods that are only used internally by the class (By using access modifiers)
The goal of a class is to provide a well-defined public interface that the user of the class can easily use to solve their problem.
Examples:
Account
Employee
Image
std::vector
std::string
Created from a class
Represents a specific instance of a class
Can create many objects out of a class
Each has its own identity
Each can use the defined class methods
Examples:
Jack's account is an instance of an Account
.
Sunny's account is an instance of an Account
.
Each has its own balance, can make deposits, withdrawals, etc.
Player
class and objects
xxxxxxxxxx
131// Class declaration
2
3class Player
4{
5 // Attributes (or instance variables)
6 std::string name;
7 int health;
8 int xp;
9
10 // Methods
11 void talk(std::string text_to_say);
12 bool is_dead();
13};
xxxxxxxxxx
71// Object instantiataion
2
3Player jack;
4Player hero;
5
6Player *enemy = new Player(); // Allocated dynamically on the heap
7delete enemy;
Account
class and objects
xxxxxxxxxx
121// Class declaration
2
3class Account
4{
5 // Attributes (or instance variables)
6 std::string name;
7 double balance;
8
9 // Method
10 bool withdraw(double amount);
11 bool deposit(double amount);
12};
xxxxxxxxxx
101Account jack_account;
2Account sunny_account;
3
4Account *yena_account = new Account(); // Allocated dynamically on the heap
5delete yena_account;
6
7Account accounts[] {jack_account, sunny_account};
8
9std::vector<Account> accounts1 {jack_account};
10accounts1.push_back(sunny_account);
Once declared, a class can be used just like any other C++ primitive data types.
You can access class attributes and class methods.
Some class members will not be accessible (i.e., hidden members)
Need an object to access instance variables
If you have an object, you can access the class members by using the dot operator (.
).
xxxxxxxxxx
41Account jack_account;
2
3jack_account.balance;
4jack_account.deposit(1000.00);
If you have a pointer to an object, you can access the class members by using the arrow operator or member of pointer operator (->
).
xxxxxxxxxx
91Account jack_account = new Account();
2
3// 1. Dereference the poiner, then use the dot operator
4(*jack_account).balance;
5(*jack_account).deposit(1000.00);
6
7// 2. Use the arrow operator (member of pointer operator)
8jack_account->balance;
9jack_account->deposit(1000.00);
public
, private
, protected
)public
- Accessible everywhere
private
- Accessible only by other members of the same class or by friends of the class
protected
- Used with inheritance
Player
class
xxxxxxxxxx
101class Player
2{
3private:
4 std::string name;
5 int health;
6 int xp;
7public:
8 void talk(std::string text_to_say);
9 bool is_dead();
10};
xxxxxxxxxx
101Player jack;
2jack.name = "Jack"; // Compiler error
3jack.health = 1000; // Compiler error
4jack.talk("Hello!"); // OK
5
6Player *enemy = new Player();
7enemy->xp = 100; // Compiler error
8enemy->talk("Got you!");// OK
9
10delete enemy;
If you try to directly access a private class member from outside of the class, you will get a compiler error.
Account
class
xxxxxxxxxx
91class Account
2{
3private:
4 std::string name;
5 double balance;
6public:
7 bool withdraw(double amount);
8 bool deposit(double amount);
9};
xxxxxxxxxx
111Account jack_account;
2jack_ccount.balance = 1000.00; // Compiler error
3jack_account.deposit(1000.00); // OK (Accessing a private member through another member of the class)
4jack_account.name = "Jack's Account"; // Compiler error
5
6Account *sunny_account = new Account();
7
8sunny_account->balance = 10000.0; // Compiler error
9sunny_account->withdraw(10000.0); // OK
10
11delete sunny_account;
This is very powerful, because, for example, if we have an object whose balance is 20 million dollars and we know that that must have been an error, then the only place where that error could have happened in this example is in the deposit method. There's no way that any other part of the program could have changed that value since the value is private.
This makes testing and debugging code much easier.
Very similar to how we implemented functions
Member methods have access to member attributes (Don't need to pass them as arguments as we do with regular functions!)
Can be implemented inside the class declaration
If you do this, the method becomes implicitly inline.
While this is okay for small and relatively simple methods, it is a good practice to implement larger, more complex methods outside of the class declaration.
Can be implemented outside the class declaration
To do this you need to use Class_name::method_name
to tell the compiler that you are implementing a method for a specific class.
The compiler can then type check the method implementation when it sees them.
Can separate specification from implementation. This makes the class much easier to manage.
.h
/.hpp
file for the class declaration
cpp
file for the class implementation
Implementing member methods INSIDE the class declaration
xxxxxxxxxx
81class Account
2{
3private:
4 double balance;
5public:
6 void set_balance(double bal) { balance = bal; }
7 double get_balance() { return balance; }
8};
Implementing member methods OUTSIDE the class declaration
xxxxxxxxxx
111class Account
2{
3private:
4 double balance;
5public:
6 void set_balance(double_bal);
7 double get_balance();
8};
9
10void Account::set_balance(double bal) { balance = bal; }
11double Account::get_balance() { return balance; }
Need to tell the compiler that you are implementing a method for a specific class. The compiler can then type check the method implementation when it sees them.
Separating specification from implementation
xxxxxxxxxx
171/* Account.h (Specification) */
2
3/* Include guard */
4
5
6
7// Account class declaration
8class Account
9{
10private:
11 double balance;
12public:
13 void set_balance(double bal);
14 double get_balance();
15};
16
17
The include guard can be replaced by
#pragma once
. But, do check first if your compiler support this directive, because some don't!
xxxxxxxxxx
61/* Account.cpp (Implementation) */
2
3
4
5void Account::set_balance(double bal) { balance = bal; }
6double Account::get_balance() { return balance; }
Notice that we included
accoun.h
and it's in double quotes. Includes with double quotes tell the compiler to include header files that are local to this project. The compiler knows where those are.Includes with angled brackets with no extensions (e.g.,
#include <iostream>
) are used to include system header files and the compiler knows where these are located.
Main file
xxxxxxxxxx
141/* main.cpp */
2
3
4
5
6int main()
7{
8 Account jack_account;
9 jack_account.set_balance(1000.00);
10 double bal = jack_account.get_balance();
11
12 std::cout << bal << std::endl; // 1000
13 return 0;
14}
Include
.h
files and never include.cpp
files!When the program is compiled, both the
main.cpp
and theaccount.cpp
files are compiled and then linked to produce the executable.