Skip to content
Theory · Classes and OOP · lesson 1 of 15

struct, class and access

What you'll learn

What you'll learn:

  • bundle data and the functions that work on it into one class;
  • hide fields from outside code and set them with a constructor;
  • call, through a reference to a base class, the version of a method that belongs to the real object;
  • notice when a copy of a derived object loses its own part.
A mechanical tally counter in cutaway: the button add(), the window value() and the wheels count_ locked inside the case

Picture a mechanical tally counter, the kind used to count visitors at a door. Inside it are wheels with digits: that is its data. On the outside there are two things:

  • a button that adds one;
  • a window that shows the number.

You cannot turn the wheels with a finger: the case is closed, and only the button changes the number. That is why the counter never shows a number nobody clicked.

In C++ such a device is described by a class. The data and the actions on it are gathered into one type, and the class decides what is reachable from outside. A class has no plastic case: the compiler checks the closed parts when it builds the program.

Let's start with gathering data into one whole. A rectangle is described by two numbers: its width and its height. Kept in separate variables, they can be confused with another rectangle's sizes, and an area function must take both numbers. The struct keyword gathers such data into one new type:

C++
#include <iostream>

struct Rect {
    int width = 0;
    int height = 0;
    int area() { return width * height; }
};

int main() {
    Rect r;
    r.width = 3;
    r.height = 4;
    std::cout << r.area() << '\n';  // 12
}

Fields and methods

Rect is a class: a type that keeps data together with the functions that work on it. The variables inside a class are its data members, or fields, and the functions are its member functions, or methods.

Describing a class creates no objects, in the same way that a drawing of a tally counter is not a counter. The variable r is an object of type Rect, and every object has its own fields. A field gets its initial value with = or braces, as in int width = 0;. Parentheses do not work here.

The fields and methods of an object are reached with a dot: r.width, r.area(). A method is always called for a particular object, and inside the method the field names mean the fields of that object. In the call r.area(), the name width is r.width.

Fields with the same access are laid out in the object in the order they are declared. But sizeof(Rect) may turn out larger than the sum of the field sizes. The compiler may add unused bytes between fields and at the end, so each field gets an address convenient for the processor.

public and private

The public: and private: labels set who can use the fields and methods. Everything after public: is open to any code, and everything after private: is open only to the class's own methods. Outside code cannot corrupt a private field: only the methods change it, and they keep its value valid.

C++
class Counter {
public:
    void add() {
        ++count_;
    }
    int value() {
        return count_;
    }

private:
    int count_ = 0;
};

Counter works like the tally counter: add() is the button, value() is the window, and the private field count_ is the wheels inside the case. For an object Counter c;, outside code can call c.add() and c.value(), but the line c.count_ = 100; does not compile. A trailing underscore in the name is a common convention for private fields.

struct and class differ only in their default access. In a struct, fields and methods without a label are public; in a class, they are private. That is why struct is usually written for bundles of public data, and class when a type has private fields.

Common mistake

The type is declared with class, and the public: label is forgotten:

C++
class Rect {
    int width = 0;
    int height = 0;
};

int main() {
    Rect r;
    r.width = 3;  // ✗
}
TEXT
error: 'width' is a private member of 'Rect'

In a class, fields without a label are private, so main cannot reach the field width. If the type is a bundle of public data, declare it with struct. If the fields need to stay private, add public methods that change them.

Key points

  • A class gathers fields and methods into one type, and every object has its own fields.
  • A method is called for an object with a dot, and the field names inside it mean that object's fields.
  • A field after private: is open only to the class's own methods.
  • struct and class differ only in default access: everything is public in a struct and private in a class.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way