Skip to content

🔒 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

ModifierSame ClassDerived ClassOutside
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:

  1. Password never public
  2. Never store plain-text — always hash
  3. Expose behavior (login), not data (password)

📚 Tổng kết

ConceptKey Takeaway
publicInterface cho outside world
privateInternal implementation (default cho class)
protectedShared với derived classes
Data HidingẨn how, expose what
friendEscape hatch — dùng tiết kiệm
class vs structclass = private default, struct = public default

➡️ Tiếp theo

Tiếp theo: The this Pointer — Self-reference trong C++.