Skip to content
Laviyx Learn

Try

C++ course menu

C++ Classes and Objects: Members, Methods, public and private

Learn C++ classes and objects: defining a class, data members and member functions, public and private access, const member functions, the this pointer, defining methods outside the class, and class vs struct.

Intermediate13 min readUpdated
On this page

Object-oriented programming (OOP) organizes a program around objects: things that combine data (what they know) with behaviour (what they can do). A class is the blueprint, and an object is one thing built from it. A BankAccount class describes what every account has and can do; your account and my account are two objects of that class.

A first class#

C++
#include <iostream>
#include <string>

class BankAccount {
public:
    std::string owner;
    double balance = 0;

    void deposit(double amount) {
        balance += amount;
    }

    void print() const {
        std::cout << owner << ": " << balance << '\n';
    }
};

int main() {
    BankAccount a;
    a.owner = "Asha";
    a.deposit(500);

    BankAccount b;
    b.owner = "Ravi";
    b.deposit(1200);
    b.deposit(300);

    a.print();
    b.print();
}
Output
Asha: 500
Ravi: 1500
  • Data members (owner, balance) store each object's state. Every object has its own copy.
  • Member functions (methods) such as deposit and print act on the object they are called on.
  • Call a method with a dot: a.deposit(500). Inside the method, balance means this object's balance.

public and private#

Right now, any code can do a.balance = -1000000;. Classes protect their data with access specifiers:

  • public: usable by any code.
  • private: usable only inside the class's own member functions.
C++
#include <iostream>
#include <string>

class BankAccount {
public:
    void set_owner(const std::string& name) { owner_ = name; }

    bool deposit(double amount) {
        if (amount <= 0) return false;
        balance_ += amount;
        return true;
    }

    bool withdraw(double amount) {
        if (amount <= 0 || amount > balance_) return false;
        balance_ -= amount;
        return true;
    }

    double balance() const { return balance_; }

private:
    std::string owner_;
    double balance_ = 0;
};

int main() {
    BankAccount acc;
    acc.set_owner("Asha");
    acc.deposit(1000);

    std::cout << std::boolalpha;
    std::cout << acc.withdraw(300) << ' ' << acc.withdraw(5000) << '\n';
    std::cout << acc.balance() << '\n';
    // acc.balance_ = 1e9;   // error: 'balance_' is private
}
Output
true false
700

Now the only way to change the balance is through deposit and withdraw, which enforce the rules. This is encapsulation, the subject of Encapsulation. The trailing underscore in balance_ is a common convention for private members; it avoids a clash with the balance() method.

const member functions#

double balance() const promises not to change the object. Mark every method that only reads data as const: the compiler checks the promise, and only const methods can be called on a const object or through a const&:

C++
#include <iostream>

class Counter {
public:
    void increment() { ++count_; }
    int value() const { return count_; }

private:
    int count_ = 0;
};

void show(const Counter& c) {
    std::cout << c.value() << '\n';   // OK: value() is const
    // c.increment();                 // error: increment() is not const
}

int main() {
    Counter c;
    c.increment();
    c.increment();
    show(c);
}
Output
2

The this pointer#

Inside a member function, this is a pointer to the object the method was called on. You rarely need it, but it is useful to return the object itself, which allows method chaining:

C++
#include <iostream>
#include <string>

class Message {
public:
    Message& add(const std::string& part) {
        text_ += part;
        return *this;   // return this object, by reference
    }
    const std::string& text() const { return text_; }

private:
    std::string text_;
};

int main() {
    Message m;
    m.add("Hello").add(", ").add("C++");
    std::cout << m.text() << '\n';
}
Output
Hello, C++

Defining methods outside the class#

For longer methods, declare them in the class and define them afterwards (usually in a separate .cpp file), using ClassName:: to say which class they belong to:

C++
#include <iostream>

class Rectangle {
public:
    double width = 0;
    double height = 0;

    double area() const;
    double perimeter() const;
};

double Rectangle::area() const {
    return width * height;
}

double Rectangle::perimeter() const {
    return 2 * (width + height);
}

int main() {
    Rectangle r{4, 2.5};
    std::cout << r.area() << ' ' << r.perimeter() << '\n';
}
Output
10 13

In a real project, the class definition goes in rectangle.h and the method definitions in rectangle.cpp.

Objects in containers#

Objects work like any other value: you can store them in vectors, pass them to functions and return them:

C++
#include <iostream>
#include <string>
#include <vector>

class Item {
public:
    Item(std::string name, double price) : name_(std::move(name)), price_(price) {}
    const std::string& name() const { return name_; }
    double price() const { return price_; }

private:
    std::string name_;
    double price_;
};

int main() {
    std::vector<Item> cart = {{"Pen", 25}, {"Notebook", 60}, {"Bag", 799}};

    double total = 0;
    for (const Item& item : cart) {
        total += item.price();
    }
    std::cout << cart.size() << " items, total " << total << '\n';
}
Output
3 items, total 884

Item(std::string name, double price) : ... is a constructor, which sets up a new object. The next lesson, Constructors and Destructors, covers them in detail.

class vs struct#

class and struct are the same feature, with one difference: members of a class are private by default, and members of a struct are public by default. Use struct for plain bundles of data, and class when the type protects its data and has behaviour.

Common mistakes#

Practice#

Practice exercise

Write a class Temperature that stores degrees Celsius privately, with set_celsius(double), celsius() const and fahrenheit() const. Set it to 25 and print both values.

Show solution
C++
#include <iostream>

class Temperature {
public:
    void set_celsius(double c) { celsius_ = c; }
    double celsius() const { return celsius_; }
    double fahrenheit() const { return celsius_ * 9 / 5 + 32; }

private:
    double celsius_ = 0;
};

int main() {
    Temperature t;
    t.set_celsius(25);
    std::cout << t.celsius() << " C = " << t.fahrenheit() << " F\n";
}
Output
25 C = 77 F

Fahrenheit is calculated when asked, rather than stored, so the two values can never disagree.

Key takeaway#

Finished this lesson?