Skip to content

Classes and Objects — Class Definitions, Access Specifiers, this Pointer

DodaTech Updated 2026-06-28 7 min read

In this tutorial, you will learn about Classes and Objects. We cover key concepts, practical examples, and best practices to help you master this topic.

C++ classes are user-defined types that encapsulate data and behavior behind public, protected, and private access specifiers, with the implicit this pointer enabling self-referencing member functions.

What You'll Learn

You will define classes with member variables and member functions, understand public, private, and protected access specifiers, use the this pointer inside member functions, create objects on the stack and heap, separate interface (header) from implementation (source file), and compare classes with structs.

Why It Matters

Classes are the foundation of object-oriented programming in C++. They let you bundle related data and operations into a single unit. The access specifier system enforces Encapsulation: you decide exactly what parts of your class are visible to users. This is how large C++ projects maintain sanity across millions of lines of code.

Learning Path

graph LR
    A["10: Functions"] --> B["11: Classes & Objects"]
    B --> C["12: Constructors"]
    C --> D["13: Destructors"]
    D --> E["14: Encapsulation"]
    style A fill:#4a90d9,stroke:#2c5f8a,color:#fff
    style B fill:#4a90d9,stroke:#2c5f8a,color:#fff
    style C fill:#4a90d9,stroke:#2c5f8a,color:#fff
    style D fill:#4a90d9,stroke:#2c5f8a,color:#fff
    style E fill:#4a90d9,stroke:#2c5f8a,color:#fff

Defining a Class

#include <iostream>
#include <string>

class Rectangle {
private:
    double width_;
    double height_;
    
public:
    void setDimensions(double w, double h) {
        width_ = w;
        height_ = h;
    }
    
    double area() const {
        return width_ * height_;
    }
    
    double perimeter() const {
        return 2 * (width_ + height_);
    }
};

int main() {
    Rectangle rect;
    rect.setDimensions(5.0, 3.0);
    
    std::cout << "Area: " << rect.area() << "\n";
    std::cout << "Perimeter: " << rect.perimeter() << "\n";
    
    return 0;
}

Access Specifiers

  • private: members accessible only within the class itself (default for class)
  • public: members accessible from anywhere
  • protected: members accessible within the class and derived classes (covers in Lesson 15)
class BankAccount {
private:
    double balance_;  // only member functions can touch this
    
public:
    void deposit(double amount) {
        if (amount > 0) balance_ += amount;
    }
    
    double getBalance() const {
        return balance_;
    }
};

int main() {
    BankAccount account;
    // account.balance_ = 1000;  // Error: private
    account.deposit(1000);
    std::cout << account.getBalance() << "\n";
}

The this Pointer

Inside a member function, this is an implicit pointer to the object on which the function was called.

#include <iostream>

class Point {
private:
    int x_, y_;
    
public:
    void setX(int x) { this->x_ = x; }
    void setY(int y) { this->y_ = y; }
    
    void set(int x, int y) {
        this->x_ = x;
        this->y_ = y;
    }
    
    Point* getThis() { return this; }
    
    void print() const {
        std::cout << "(" << x_ << ", " << y_ << ")\n";
    }
};

int main() {
    Point p1, p2;
    p1.set(3, 4);
    p2.set(5, 6);
    
    p1.print();
    p2.print();
    
    std::cout << (p1.getThis() == &p1) << "\n";  // 1 (true)
    
    // Method chaining using this
    Point* ptr = &p1;
    ptr->setX(10);
    ptr->setY(20);
    ptr->print();
}

this is most commonly used to:

  • Distinguish parameter names from member names
  • Return *this from member functions to enable method chaining
  • Pass the current object to another function

Separating Interface from Implementation

rectangle.h

#ifndef RECTANGLE_H
#define RECTANGLE_H

class Rectangle {
private:
    double width_;
    double height_;
    
public:
    void setDimensions(double w, double h);
    double area() const;
    double perimeter() const;
};

#endif

rectangle.cpp

#include "rectangle.h"

void Rectangle::setDimensions(double w, double h) {
    width_ = w;
    height_ = h;
}

double Rectangle::area() const {
    return width_ * height_;
}

double Rectangle::perimeter() const {
    return 2 * (width_ + height_);
}

main.cpp

#include <iostream>
#include "rectangle.h"

int main() {
    Rectangle r;
    r.setDimensions(4, 7);
    std::cout << r.area() << "\n";
}

The :: is the scope resolution operator. Rectangle::setDimensions means "the setDimensions function that belongs to the Rectangle class."

Class vs struct

struct Point {
    int x;  // public by default
    int y;
};

class Circle {
    double radius_;  // private by default
public:
    void setRadius(double r) { radius_ = r; }
    double area() const { return 3.14159 * radius_ * radius_; }
};

int main() {
    Point p;
    p.x = 10;  // OK: struct members are public
    
    Circle c;
    // c.radius_ = 5;  // Error: private
    c.setRadius(5);
}

In C++, struct and class are identical except:

  • struct has public access by default
  • class has private access by default

Convention: use struct for simple data aggregates (plain old data) and class for types with invariants and private data.

Const Member Functions

class Counter {
private:
    int count_ = 0;
public:
    void increment() { ++count_; }          // non-const
    int value() const { return count_; }    // const: can call on const objects
};

void printCounter(const Counter& c) {
    std::cout << c.value() << "\n";  // OK: value() is const
    // c.increment();  // Error: increment() is non-const
}

Mark all member functions that do not modify the object as const. This allows them to be called on const objects and references.

Common Mistakes

Mistake 1: Forgetting Semicolon After Class Definition

class MyClass { };  // semicolon required

Mistake 2: Non-const Member Called on Const Object

const Rectangle r;
r.setDimensions(3, 4);  // Error if setDimensions is not const

Make all getters and read-only operations const.

Mistake 3: Accessing Private Members from Outside

class Foo { private: int x; };
Foo f;
f.x = 5;  // Error

Use public getters/setters or make the member public if encapsulation is not needed.

Mistake 4: Missing Include Guard

// myclass.h  — without header guard, double-inclusion causes error

Always use #ifndef, #define, #endif or #pragma once.

Mistake 5: Confusing . and ->

Rectangle r;
Rectangle* p = &r;
r.area();    // dot for objects
p->area();   // arrow for pointers
(*p).area(); // equivalent to arrow

Mistake 6: Using this Unnecessarily

void setX(int x) { x_ = x; }  // fine without this-> if member names differ

Only need this-> when parameter names shadow member names.

Practice Questions

  1. What is the default access level in a class? In a struct?
  2. Write a Time class with hours, minutes, seconds (private) and getters/setters (public).
  3. What does this point to inside a member function?
  4. Why would you mark a member function as const?
  5. Write a class that uses method chaining (member functions returning *this).

Challenge

Design a Fraction class with private numerator and denominator, public add, subtract, multiply, divide methods that return Fraction, and a simplify method using GCD. Mark const-correctly.

FAQ

What is the difference between a class and an object?

A class is a blueprint (type). An object is an instance of that class (variable). Many objects can be created from one class.

Can I have a class without any members?

Yes. An empty class has size 1 (to ensure each object has a unique address).

What is the purpose of private members?

Encapsulation: hiding implementation details from users of the class. This allows you to change internal implementation without affecting external code.

Is `this` always necessary inside member functions?

No. In most cases you can access members directly without this->. It is only required when a parameter name shadows a member name.

Can I put a function definition inside a class?

Yes. Functions defined inside the class body are implicitly inline. For larger functions, separate the declaration (in header) from definition (in .cpp file).

What is the difference between `class` and `typename` in template parameters?

They are interchangeable in template parameter lists. class was the original keyword; typename was added later to avoid ambiguity.

Mini Project

Build a Student class:

#include <iostream>
#include <string>
#include <vector>

class Student {
private:
    std::string name_;
    std::string id_;
    std::vector<double> grades_;
    
public:
    Student(const std::string& name, const std::string& id)
        : name_(name), id_(id) {}
    
    void addGrade(double grade) {
        if (grade >= 0.0 && grade <= 100.0) {
            grades_.push_back(grade);
        }
    }
    
    double average() const {
        if (grades_.empty()) return 0.0;
        double sum = 0.0;
        for (double g : grades_) {
            sum += g;
        }
        return sum / grades_.size();
    }
    
    char letterGrade() const {
        double avg = average();
        if (avg >= 90) return 'A';
        if (avg >= 80) return 'B';
        if (avg >= 70) return 'C';
        if (avg >= 60) return 'D';
        return 'F';
    }
    
    void print() const {
        std::cout << name_ << " (" << id_ << "): "
                  << average() << "% -> " << letterGrade() << "\n";
    }
};

int main() {
    Student alice("Alice Smith", "S12345");
    alice.addGrade(85);
    alice.addGrade(92);
    alice.addGrade(78);
    alice.print();
}

What's Next

Classes let you define custom types. The next lesson covers constructors: default, parameterized, copy, and move constructors, plus the member initializer list.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro