Giao diện
🔒 Access Modifiers — Phạm vi truy cập
Access modifiers là công cụ bảo vệ data. Chúng quyết định ai được phép truy cập thành phần nào của class.
Ba Access Modifiers
cpp
class MyClass {
public: // 🌍 Ai cũng access được
int publicVar;
void publicMethod();
private: // 🔒 Chỉ class này access được
int privateVar;
void privateMethod();
protected: // 🛡️ Class này + derived classes
int protectedVar;
void protectedMethod();
};public — Mở cho tất cả
cpp
#include <iostream>
class Counter {
public:
int count = 0; // Ai cũng access được
void increment() {
++count;
}
void display() {
std::cout << "Count: " << count << std::endl;
}
};
int main() {
Counter c;
c.increment(); // ✅ OK
c.display(); // ✅ OK
c.count = 100; // ✅ OK — nhưng có nên?
c.count = -999; // ✅ OK — VẤN ĐỀ: không validate!
return 0;
}⚠️ Vấn đề với public data
- Không kiểm soát được ai thay đổi
- Không validate được giá trị
- Thay đổi implementation sẽ break code bên ngoài
private — Chỉ class mới access được
cpp
#include <iostream>
class SafeCounter {
private:
int count_ = 0; // 🔒 Hidden from outside
int maxCount_ = 100;
public:
void increment() {
if (count_ < maxCount_) {
++count_;
}
}
void decrement() {
if (count_ > 0) {
--count_;
}
}
int getCount() const { // Read-only access
return count_;
}
};
int main() {
SafeCounter sc;
sc.increment(); // ✅ OK
std::cout << sc.getCount() << std::endl; // ✅ OK
// sc.count_ = -999; // ❌ Error: private!
// sc.maxCount_ = 1000; // ❌ Error: private!
return 0;
}Data Hiding — Ẩn Implementation Details
Ví dụ: Temperature Class
cpp
#include <iostream>
class Temperature {
private:
double celsius_; // Luôn lưu dưới dạng Celsius internally
public:
explicit Temperature(double celsius) : celsius_(celsius) {}
// Getters — expose nhiều format
double getCelsius() const { return celsius_; }
double getFahrenheit() const { return celsius_ * 9.0/5.0 + 32; }
double getKelvin() const { return celsius_ + 273.15; }
// Setters — nhận nhiều format
void setCelsius(double c) { celsius_ = c; }
void setFahrenheit(double f) { celsius_ = (f - 32) * 5.0/9.0; }
void setKelvin(double k) { celsius_ = k - 273.15; }
};
int main() {
Temperature t(25.0); // 25°C
std::cout << t.getCelsius() << "°C" << std::endl; // 25
std::cout << t.getFahrenheit() << "°F" << std::endl; // 77
std::cout << t.getKelvin() << "K" << std::endl; // 298.15
// User không cần biết internal format!
t.setFahrenheit(100);
std::cout << t.getCelsius() << "°C" << std::endl; // 37.78
return 0;
}Lợi ích của Data Hiding:
┌─────────────────────────────────────────────────────────────────┐
│ DATA HIDING BENEFITS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ BEFORE (public data): AFTER (private + methods): │
│ ────────────────── ────────────────────────── │
│ │
│ class Temp { class Temp { │
│ public: private: │
│ double celsius; double celsius_; │
│ double fahrenheit; public: │
│ }; double getCelsius() const; │
│ double getFahrenheit() const; │
│ }; │
│ │
│ ❌ Phải sync 2 values ✅ Một source of truth │
│ ❌ Bug nếu không nhất quán ✅ Luôn consistent │
│ ❌ Đổi impl → break users ✅ Đổi impl không ảnh hưởng │
│ │
└─────────────────────────────────────────────────────────────────┘protected — Cho Inheritance
cpp
#include <iostream>
class Animal {
private:
std::string secretDNA_ = "ATCG..."; // Không ai thấy
protected:
std::string name_; // Derived classes có thể dùng
int age_;
public:
Animal(const std::string& name, int age)
: name_(name), age_(age) {}
void introduce() const {
std::cout << "I'm " << name_ << std::endl;
}
};
class Dog : public Animal {
public:
Dog(const std::string& name, int age)
: Animal(name, age) {}
void bark() const {
// ✅ Access protected member from base
std::cout << name_ << " says: Woof!" << std::endl;
// ❌ Cannot access private
// std::cout << secretDNA_ << std::endl; // Error!
}
};
int main() {
Dog buddy("Buddy", 3);
buddy.introduce(); // I'm Buddy
buddy.bark(); // Buddy says: Woof!
// ❌ Outside cannot access protected
// std::cout << buddy.name_ << std::endl; // Error!
return 0;
}Summary: Access Levels
| Modifier | Same Class | Derived Class | Outside |
|---|---|---|---|
public | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ❌ |
private | ✅ | ❌ | ❌ |
class vs struct Default Access
cpp
// class: mặc định private
class MyClass {
int x; // private
public:
int y;
};
// struct: mặc định public
struct MyStruct {
int x; // public
private:
int y;
};📌 HPN Convention
class: Cho OOP với encapsulation (có private)struct: Cho POD (Plain Old Data) — all public, no methods
friend — Cho phép truy cập private
Friend Function
cpp
#include <iostream>
class Box {
private:
double width_, height_, depth_;
public:
Box(double w, double h, double d)
: width_(w), height_(h), depth_(d) {}
// Khai báo friend function
friend double calculateVolume(const Box& b);
};
// Friend function có thể access private!
double calculateVolume(const Box& b) {
return b.width_ * b.height_ * b.depth_; // ✅ Access private
}
int main() {
Box box(2, 3, 4);
std::cout << "Volume: " << calculateVolume(box) << std::endl; // 24
return 0;
}Friend Class
cpp
class Engine {
private:
int horsepower_;
friend class Mechanic; // Mechanic có thể xem private
public:
explicit Engine(int hp) : horsepower_(hp) {}
};
class Mechanic {
public:
void diagnose(const Engine& e) {
// ✅ Access private nhờ friend
std::cout << "Engine has " << e.horsepower_ << " HP" << std::endl;
}
};⚠️ Friend breaks encapsulation
Dùng friend một cách tiết kiệm. Nó break encapsulation bằng cách cho access vào private. Chỉ dùng khi:
- Operator overloading (như
<<cho streams) - Factory patterns
- Test classes
🐛 Bug Hunt Challenge
🐛 Bug Hunt
Có vấn đề gì với design này?
cpp
# SECURITY: Never hardcode credentials in production code
# Use environment variables or secure credential management systems
class User {
public:
std::string password; // ???
bool login(const std::string& inputPwd) {
return inputPwd == password;
}
};
int main() {
User u;
u.password = ENV["DB_PASSWORD"];
// Attacker code:
std::cout << "Password is: " << u.password << std::endl;
return 0;
}🔍 Giải thích & Fix
Vấn đề: Password là public → ai cũng đọc được!
Fix:
cpp
class User {
private:
std::string passwordHash_; // Store hash, not plain text!
public:
void setPassword(const std::string& pwd) {
passwordHash_ = hashFunction(pwd); // Hash before storing
}
bool login(const std::string& inputPwd) {
return hashFunction(inputPwd) == passwordHash_;
}
};Key Principles:
- Password never public
- Never store plain-text — always hash
- Expose behavior (login), not data (password)
📚 Tổng kết
| Concept | Key Takeaway |
|---|---|
public | Interface cho outside world |
private | Internal implementation (default cho class) |
protected | Shared với derived classes |
| Data Hiding | Ẩn how, expose what |
friend | Escape hatch — dùng tiết kiệm |
| class vs struct | class = private default, struct = public default |
➡️ Tiếp theo
Tiếp theo: The this Pointer — Self-reference trong C++.