cs.thefarshad
medium

Classes & Objects

Bundle data with behavior — constructors, destructors, and encapsulation define an object's whole lifecycle.

A class is a blueprint that bundles data (member variables) together with the functions that operate on that data (member functions). An object is a concrete instance of that blueprint, living in memory. This pairing of state and behavior is the heart of object-oriented programming in C++.

Every object has a lifecycle: it is constructed, used, and finally destructed when it goes out of scope. The compiler runs a constructor at birth and a destructor at death — automatically. Step through the program below to watch an object’s members get initialized, mutated by a member function, and then cleaned up at the closing brace.

> struct Account {
std::string owner; // member
int cents; // member
Account(std::string n, int c)
: owner(n), cents(c) {} // constructor
void deposit(int d) { cents += d; }
~Account() { /* cleanup */ } // destructor
};
{
Account a("Ada", 500); // construct
a.deposit(250); // use member fn
} // a goes out of scope -> destruct
Account adeclared
ownerstd::string
centsint
one contiguous object — members stored together
1constructing
2alive
3destructing
1/8
A class bundles data (members) with the functions that operate on it. No object exists yet.

Defining a class

A class groups members and the operations on them. The public and private labels control encapsulation: who is allowed to touch each member.

#include <string>

class Account {
private:                 // hidden implementation details
    std::string owner_;
    int cents_;

public:                  // the interface other code may use
    Account(std::string owner, int cents)   // constructor
        : owner_(std::move(owner)), cents_(cents) {}

    ~Account() {}        // destructor: runs at end of life

    void deposit(int amount) { cents_ += amount; }
    int balance() const { return cents_; }   // const: does not modify state
};

The line after the constructor’s name — : owner_(...), cents_(...) — is the member initializer list. It constructs each member directly, which is more efficient than assigning to them inside the body.

Construction and destruction

Constructors acquire whatever the object needs; destructors release it. Because the compiler guarantees the destructor runs at scope exit, this is the basis of RAII.

void demo() {
  Account a("Ada", 500);  // constructor runs here
  a.deposit(250);         // balance() now returns 750
  // ...
}                           // destructor for a runs here, automatically

Why encapsulation matters

By keeping cents_ private and exposing only deposit and balance, the class controls every change to its state. You could later add validation (reject negative deposits) without touching any calling code. The object’s invariants stay protected because outside code can only go through the public interface.

Takeaways

  • A class bundles data (members) with the functions that act on them; an object is an instance of it.
  • The constructor initializes an object; the destructor cleans it up at scope exit — both run automatically.
  • Prefer the member initializer list (: x_(v)) over assignment inside the constructor body.
  • Encapsulation (private data, a public interface) protects an object’s invariants and keeps code maintainable.