Introduction to Classes

In C++, structs provide a way to group related variables. You might create a struct like this:

struct Character
{
    int health{};
    int level{};
    double experience{};
};

This works well for grouping data, but what if you want to include behaviors alongside the data? Enter classes.

What is a class?

A class is a program-defined type that can contain both data (member variables) and functions (member functions). Classes are the foundation of object-oriented programming in C++.

The syntax is nearly identical to structs:

class Character
{
    int health{};
    int level{};
    double experience{};
};

Notice we use the class keyword instead of struct. That's the primary syntactic difference.

Creating objects from classes

A class is a blueprint. To use it, you create objects (also called instances) of the class:

int main()
{
    Character warrior{};   // warrior is an object of type Character
    Character mage{};      // mage is another object of type Character

    return 0;
}

Each object has its own copy of the class's data members. warrior has his own health, level, and experience. So does mage. They're independent objects of the same type.

Member variables

Variables defined inside a class are called member variables or data members. They belong to objects of that class:

class Weapon
{
    int damage{};
    double attackSpeed{};
    int durability{};
};

Each Weapon object will have its own damage, attackSpeed, and durability.

Adding member functions

Classes can also contain functions. Functions defined inside a class are called member functions or methods:

#include <iostream>

class Weapon
{
public:  // We'll explain this shortly
    int damage{};
    double attackSpeed{};
    int durability{};

    void showStats()
    {
        std::cout << "Damage: " << damage << '\n';
        std::cout << "Attack Speed: " << attackSpeed << '\n';
        std::cout << "Durability: " << durability << '\n';
    }
};

int main()
{
    Weapon sword{};
    sword.damage = 25;
    sword.attackSpeed = 1.5;
    sword.durability = 100;

    sword.showStats();

    return 0;
}

The showStats() member function can access the member variables of the object it's called on. When you call sword.showStats(), the function works with sword's data.

The public keyword

Notice the public: label in the class definition. This is an access specifier that controls who can access the class members.

  • public: Anyone can access these members
  • private: Only the class's own member functions can access these members

By default, class members are private. We'll explore access control in detail in a later lesson.

For now, use public: to make members accessible:

class Spell
{
public:
    int manaCost{};
    int damage{};

    int calculateDPS()
    {
        return damage * 2;
    }
};

Struct vs. class

The only difference between struct and class is the default access level:

  • struct: Members are public by default
  • class: Members are private by default

These are equivalent:

struct StatsA
{
    int value{};  // public by default
};

class StatsB
{
public:
    int value{};  // explicitly public
};

Convention: Use struct for simple data-only types (plain old data). Use class when you have member functions or want to control access.

Why use classes?

Classes provide several benefits:

Encapsulation: Group related data and behaviors together.

class HealthBar
{
public:
    int current{};
    int maximum{};

    void heal(int amount)
    {
        current += amount;
        if (current > maximum)
            current = maximum;
    }

    void takeDamage(int amount)
    {
        current -= amount;
        if (current < 0)
            current = 0;
    }
};

Organization: Instead of separate variables and functions scattered throughout your code, everything related to a concept lives in one place.

Object-oriented design: Classes let you model real-world concepts naturally. A HealthBar object behaves like a real health system.

A complete example

#include <iostream>

class Quest
{
public:
    int rewardGold{};
    bool isComplete{};

    void complete()
    {
        isComplete = true;
    }

    void showStatus()
    {
        if (isComplete)
            std::cout << "Quest complete! Reward: " << rewardGold << " gold\n";
        else
            std::cout << "Quest in progress...\n";
    }

    void reset()
    {
        isComplete = false;
    }
};

int main()
{
    Quest dragonSlayer{};
    dragonSlayer.rewardGold = 500;

    dragonSlayer.showStatus();   // Quest in progress...

    dragonSlayer.complete();
    dragonSlayer.showStatus();   // Quest complete! Reward: 500 gold

    return 0;
}

The Quest class bundles quest tracking data with behaviors for manipulating that data. This is cleaner than having separate variables and global functions.

Core Understanding

Classes combine data and the functions that operate on that data into unified types, forming the basis of object-oriented programming in C++.

Summary

Classes are program-defined types that can contain both data (member variables) and functions (member functions), forming the foundation of object-oriented programming in C++.

Class syntax uses the class keyword instead of struct, with the primary difference being default access levels for members.

Objects (instances) are created from classes, with each object having its own independent copy of the class's member variables.

Member variables (data members) are variables defined inside a class that belong to objects of that class, storing the object's state.

Member functions (methods) are functions defined inside a class that provide behaviors for objects, operating on the object's member variables.

Access specifiers control who can access class members—public allows anyone to access members, while private restricts access to the class's own member functions.

Default access levels differ between struct (public by default) and class (private by default), though they're otherwise identical.

Convention suggests using struct for simple data-only types and class when you have member functions or want to control access.

Encapsulation groups related data and behaviors together, making code more organized and easier to maintain.

Organization benefits come from keeping everything related to a concept in one place rather than scattered across separate variables and functions.

Object-oriented design enables modeling real-world concepts naturally, with objects behaving like their real-world counterparts.

Classes provide the mechanism for creating custom types that bundle data with the functions that operate on that data, enabling object-oriented design patterns and more intuitive code organization.