базовые концепции ООП — методыbaseline OOP concepts — methods
Метод — функция, привязанная к классу, неявно получающая доступ к полям конкретного объекта через скрытый параметр this. Три уточнения — const, ref-qualifiers и static — управляют тем, к какому виду объекта (или вообще без объекта) метод применим.A method is a function bound to a class, implicitly given access to a specific object's fields through the hidden this parameter. Three refinements — const, ref-qualifiers, and static — control what kind of object (or no object at all) a method applies to.
Метод (member function) — функция, объявленная внутри класса, имеющая неявный доступ к скрытому указателю this на объект, для которого она вызвана. Все нестатические поля и другие методы того же класса доступны внутри метода напрямую, без явной квалификации — это и есть синтаксический сахар над реальной сигнатурой, принимающей this первым аргументом.A method (member function) is a function declared inside a class, given implicit access to a hidden pointer, this, to the object it was called on. All non-static fields and other methods of the same class are accessible inside the method directly, with no explicit qualification — that's syntactic sugar over the real signature, which takes this as its first argument.
class Counter {
int count = 0;
public:
void increment() { count++; } // на деле — increment(Counter* this) { this->count++; }// really — increment(Counter* this) { this->count++; }
};
const после списка параметров означает, что внутри метода this имеет тип const T* — метод обещает вызывающей стороне не изменять наблюдаемое состояние объекта, и это обещание проверяется компилятором: попытка присвоить значение обычному (не mutable) полю внутри такого метода — ошибка компиляции.A trailing const after the parameter list means this has type const T* inside the method — the method promises the caller not to change the object's observable state, and the compiler enforces that promise: assigning to an ordinary (non-mutable) field inside such a method is a compile error.
class Vector3 {
double x, y, z;
public:
double length() const { return std::sqrt(x*x + y*y + z*z); } // не меняет объект// doesn't change the object
void normalize() { double l = length(); x /= l; y /= l; z /= l; } // меняет — не const// changes it — not const
};
void printLength(const Vector3& v) {
std::cout << v.length(); // v.normalize(); здесь было бы ошибкой — v это const-ссылка// v.normalize(); here would be an error — v is a const reference
}
Метод можно перегрузить по const — компилятор выбирает версию в зависимости от того, является ли сам объект, на котором вызывается метод, константным. Классический пример — operator[] у контейнеров, где const-версия возвращает const T&, а неconst — T&, позволяя изменение.A method can be overloaded on const — the compiler picks the version based on whether the object the method is called on is itself const. The classic example is a container's operator[], where the const version returns const T& and the non-const one returns T&, allowing modification.
С C++11 метод можно квалифицировать не только по const, но и по тому, является ли сам объект lvalue (&) или rvalue (&&) — то есть, вызывается ли метод на именованной переменной или на временном объекте. Это позволяет безопасно "украсть" внутренние ресурсы у временного объекта, не боясь испортить именованную переменную тем же кодом.Since C++11, a method can be qualified not just by const, but by whether the object itself is an lvalue (&) or an rvalue (&&) — that is, whether the method is called on a named variable or on a temporary. This allows safely "stealing" a temporary's internal resources without the same code risking corruption of a named variable.
class Buffer {
std::vector<char> data;
public:
std::vector<char> extract() && { return std::move(data); } // только для rvalue — безопасно "опустошить"// rvalue-only — safe to "empty out"
const std::vector<char>& extract() const& { return data; } // для lvalue — только чтение, без разрушения// lvalue-only — read-only, no destruction
};
Buffer b;
auto copy = b.extract(); // b — lvalue, вызовется const& версия, data цела// b is an lvalue, the const& version runs, data stays intact
auto moved = Buffer{}.extract(); // временный объект — rvalue, вызовется &&, данные перемещены// a temporary — an rvalue, the && version runs, data is moved out
На практике ref-qualifiers встречаются заметно реже, чем const-перегрузка, но именно эту нишу — «отличить временный объект от именованной переменной на уровне выбора перегрузки» — не закрывает никакой другой механизм языка.In practice, ref-qualifiers show up far less often than const overloading, but the specific niche they fill — "tell a temporary apart from a named variable at overload-resolution time" — isn't covered by any other language mechanism.
Статический метод не получает this и не имеет доступа к нестатическим полям конкретного объекта — фактически это обычная функция, просто логически сгруппированная с классом через пространство имён класса. Вызывается через имя класса, а не через объект, и может быть вызван даже без единого существующего объекта класса.A static method receives no this and has no access to any specific object's non-static fields — it's effectively an ordinary function, just logically grouped with the class through the class's namespace. It's called through the class name, not through an object, and can be called even when no object of the class exists yet.
class IdGenerator {
static inline int next_id = 0; // static поле — одно на весь класс, не на объект// a static field — one per class, not per object
public:
static int next() { return next_id++; } // static метод — работает только со static-состоянием// a static method — only works with static state
};
int a = IdGenerator::next(); // вызов через имя класса, без единого объекта IdGenerator// called through the class name, with no IdGenerator object anywhere
Типичное применение — фабричные методы (создание объекта нестандартным способом, часто под другим именем, чем конструктор) и утилитарные функции, логически относящиеся к классу, но не требующие конкретного экземпляра.The typical use is factory methods (creating an object in a non-standard way, often under a different name than the constructor) and utility functions that logically belong to the class but don't need a specific instance.
const-метод не может менять указатель-поле, но если это поле — сырой указатель, то объект, на который он указывает, менять можно свободно: const запрещает изменение самого указателя, а не данных за ним.A const method can't reassign a pointer field, but if that field is a raw pointer, the object it points to can be freely modified: const forbids changing the pointer itself, not the data behind it.
static и virtual взаимоисключающи по определению — виртуальная диспетчеризация работает через this и vtable конкретного объекта, а у статического метода нет ни того, ни другого.static and virtual are mutually exclusive by definition — virtual dispatch works through a specific object's this and vtable, and a static method has neither.
Метод без &/&& вызывается одинаково успешно и на lvalue, и на rvalue объекте — если нужно ограничить метод только именованными переменными, требуется явный &, поведение по умолчанию — не ограничивать вообще.A method with no &/&& is called equally successfully on both lvalue and rvalue objects — restricting a method to named variables only requires an explicit &; the default behavior is no restriction at all.