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++.
🧠 Quiz
Câu 1: Đoạn code sau có lỗi gì?
cpp
class Secret {
int value_ = 42;
public:
int getValue() const { return value_; }
};
int main() {
Secret s;
std::cout << s.value_;
}- [ ] A) Thiếu constructor cho
Secret - [x] B)
value_làprivate(mặc định của class), không thể truy cập từmain - [ ] C)
getValue()không thể trả vềprivatemember - [ ] D) Code hoàn toàn đúng, in ra
42
💡 Giải thích: Trong
class, access modifier mặc định làprivate. Vìvalue_nằm trướcpublic:, nó làprivate. Truy cậps.value_từ bên ngoài class sẽ gây compile error. Phải dùngs.getValue()để đọc giá trị qua public getter.
Câu 2: friend function có quyền truy cập gì?
- [ ] A) Chỉ
publicmembers - [ ] B)
publicvàprotectedmembers - [x] C) Tất cả members kể cả
private - [ ] D) Chỉ
protectedmembers
💡 Giải thích: Khi một function được khai báo
friendbên trong class, nó được cấp quyền truy cập tất cả members (public, protected, private) của class đó. Friend phá vỡ encapsulation nên chỉ nên dùng khi thực sự cần thiết, ví dụ operator overloading (operator<<).
Câu 3: Derived class có thể truy cập member nào của base class khi dùng public inheritance?
- [ ] A) Tất cả members (public, protected, private)
- [x] B) Chỉ
publicvàprotectedmembers - [ ] C) Chỉ
publicmembers - [ ] D) Không truy cập được member nào
💡 Giải thích: Với
publicinheritance, derived class có thể truy cậppublicvàprotectedmembers của base class.privatemembers không bao giờ truy cập được từ derived class — đó là nguyên tắc encapsulation. Dùngprotectedcho data cần chia sẻ với derived classes.