Třídy, struktury a zapouzdření
Understand the difference between struct and class, access specifiers, encapsulation, const member functions, static members, and modern aggregate initialization.
Co je třída?
třída v C++ je uživatelem definovaný typ, který sdružuje data (členské proměnné) a operace s těmito daty (členské funkce) do jediné jednotky. Toto spojení se nazývá zapouzdření — jeden ze čtyř pilířů OOP.
Klíčovým poznatkem je, že třída definuje invariant: sadu pravidel, která musí být vždy pravdivá o jejím vnitřním stavu. Například třídaDatemůže vyžadovat, aby byl měsíc vždy mezi 1 a 12. Zapouzdření umožňuje vynutit tyto invarianty řízením přístupu k vnitřnímu stavu.
struct vs class
In C++,structandclassare almost identical. The only difference is the default access specifier:structdefaults topublic, whileclassdefaults toprivate. Convention: usestructfor plain data aggregates,classwhen you have invariants to maintain.
#include <iostream>
#include <string>
// struct: members are public by default
struct Point {
double x; // public
double y; // public
};
// class: members are private by default
class BankAccount {
std::string owner; // private
double balance; // private
public:
BankAccount(const std::string& name, double initial)
: owner{name}, balance{initial} {}
double get_balance() const { return balance; }
void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
};
int main() {
Point p{3.0, 4.0}; // aggregate initialization
std::cout << p.x << ", " << p.y << '\n';
BankAccount acct{"Alice", 1000.0};
acct.deposit(500.0);
std::cout << acct.get_balance() << '\n'; // 1500
// acct.balance = -999; // ERROR: private member
return 0;
}Access Specifiers & the this Pointer
C++ poskytuje tři úrovně přístupu: public (přístup má kdokoli), private (pouze třída a její přátelé) a protected (třída, její přátelé a odvozené třídy). Ukazatelthisje implicitní ukazatel na aktuální objekt dostupný v každé nestatické členské funkci.
#include <iostream>
#include <string>
class Employee {
private:
std::string name_;
int id_;
protected:
double salary_; // accessible to derived classes
public:
Employee(const std::string& name, int id, double salary)
: name_{name}, id_{id}, salary_{salary} {}
// const member function: promises not to modify the object
const std::string& get_name() const { return name_; }
int get_id() const { return id_; }
// 'this' pointer usage — return *this for method chaining
Employee& set_name(const std::string& name) {
this->name_ = name; // 'this->' disambiguates
return *this;
}
Employee& set_id(int id) {
this->id_ = id;
return *this;
}
void print() const {
std::cout << "Employee{" << name_ << ", #" << id_
<< ", $" << salary_ << "}\n";
}
};
int main() {
Employee e{"Bob", 42, 75000.0};
e.set_name("Robert").set_id(43); // method chaining via *this
e.print(); // Employee{Robert, #43, $75000}
return 0;
}Static Members & Friend
Statické členy patří do třídy, nikoli do žádné instance. Použijte je pro sdílené stavové nebo pomocné funkce. Klíčové slovo friend uděluje soukromým členům přístup k nečlenské funkci nebo jiné třídě – používejte jej střídmě, protože narušuje zapouzdření.
#include <iostream>
class Widget {
int value_;
// C++17: inline static — define in header, no .cpp needed
inline static int count_ = 0;
public:
explicit Widget(int v) : value_{v} { ++count_; }
~Widget() { --count_; }
static int get_count() { return count_; }
// friend function can access private members
friend std::ostream& operator<<(std::ostream& os, const Widget& w);
};
std::ostream& operator<<(std::ostream& os, const Widget& w) {
return os << "Widget(" << w.value_ << ')'; // accesses private value_
}
int main() {
Widget a{10}, b{20};
std::cout << Widget::get_count() << '\n'; // 2
std::cout << a << '\n'; // Widget(10)
{
Widget c{30};
std::cout << Widget::get_count() << '\n'; // 3
}
std::cout << Widget::get_count() << '\n'; // 2
return 0;
}Agregovaná inicializace a určené inicializátory (C++20)
agregát je třída nebo struktura bez uživatelem deklarovaných konstruktorů, bez soukromých/chráněných nestatických datových členů, bez virtuálních funkcí a bez virtuálních základních tříd. C++20 přidává určené inicializátory, které vám umožní pojmenovat, které členy inicializujete.
#include <iostream>
#include <string>
struct Config {
std::string host = "localhost";
int port = 8080;
bool use_tls = false;
int max_connections = 100;
};
int main() {
// Traditional aggregate initialization
Config c1{"example.com", 443, true, 200};
// C++20 designated initializers — much more readable
Config c2{
.host = "api.example.com",
.port = 443,
.use_tls = true
// .max_connections uses default value 100
};
std::cout << c2.host << ':' << c2.port << '\n';
std::cout << "TLS: " << std::boolalpha << c2.use_tls << '\n';
std::cout << "Max: " << c2.max_connections << '\n'; // 100
return 0;
}Ve výchozím nastavení nastavte datové členy na soukromé a zpřístupněte pouze to, co je potřeba, prostřednictvím minimálního veřejného rozhraní. Pokud třída nemá žádný invariant k údržbě (je to jen svazek dat), použijte místo toho struct s veřejnými členy. Nepřidávejte getry a settery pro každé pole – to maří účel zapouzdření. Místo toho poskytněte smysluplné operace jakodeposit()awithdraw()spíše nežset_balance().
Pokud členská funkce nemění stav objektu, označte jejconst. Bezconstnemůžete volat funkci na objektuconstnebo prostřednictvím odkazuconst— což se stává neustále při předávání objektů pomocíconst&. Chybějícíconstna přístupovém objektu je běžným zdrojem chyb při kompilaci ve větších kódových základnách.
structaclassse liší pouze výchozím přístupem:structje veřejný,classje soukromý- Zapouzdření chrání invarianty třídy – používejte data
privatese smysluplným veřejným rozhraním - Označte nemutující členské funkce
const, aby fungovaly s odkazyconst - Pro statické členy definované v záhlaví použijte
inline static(C++17). - Inicializátory určené pro C++20 činí agregovanou inicializaci čitelnou a samodokumentující
friendby měl být používán střídmě – obvykle pro přetížení operátorů, kteří potřebují soukromý přístup
Kvíz — Otestujte své znalosti
(15 XP)1. Jaký je JEDINÝ rozdíl mezi`struct`a`class`v C++?
2. Proč byste měli označit členské funkce přístupového objektu jako`const`?
3. What does`inline static int count_ = 0;`achieve in C++17?