C++98corebeginner
Encapsulation
C++98 · The Foundation · Compiler flag: -std=c++98
Explanation
Hides data using access specifiers to control access.
Real-World Scenario
Protect a bank account’s balance from direct modification.
Quick Snippet
snippet.cpp
class Account { private: int balance; public: int getBalance() {} };Full Example
encapsulation.cpp
// CodeNebula - C++98 Example: Encapsulation
// Compile: g++ -std=c++98 -Wall -Wextra -o example encapsulation.cpp
//
// This example demonstrates:
// - Private data members hidden from outside access
// - Public getter/setter methods as the controlled interface
// - Validation in setters to enforce invariants
// - Why encapsulation matters: data integrity and flexibility
#include <iostream>
#include <cstring>
// ============================================================
// 1. BankAccount: encapsulated balance with validation
// ============================================================
class BankAccount {
private:
// --- Hidden internal state ---
char owner[64];
double balance;
int accountNumber;
// Private helper
static int nextAccountNumber;
public:
BankAccount(const char* name, double initialDeposit) : balance(0.0) {
std::strncpy(owner, name, 63);
owner[63] = '\0';
accountNumber = ++nextAccountNumber;
// Validate initial deposit
if (initialDeposit > 0.0) {
balance = initialDeposit;
}
std::cout << " Account #" << accountNumber
<< " created for " << owner << std::endl;
}
// --- Getters (read-only access) ---
const char* getOwner() const { return owner; }
double getBalance() const { return balance; }
int getAccountNumber() const { return accountNumber; }
// --- Setters with validation ---
bool deposit(double amount) {
if (amount <= 0.0) {
std::cout << " ERROR: deposit amount must be positive" << std::endl;
return false;
}
balance += amount;
std::cout << " Deposited $" << amount
<< " -> Balance: $" << balance << std::endl;
return true;
}
bool withdraw(double amount) {
if (amount <= 0.0) {
std::cout << " ERROR: withdrawal amount must be positive" << std::endl;
return false;
}
if (amount > balance) {
std::cout << " ERROR: insufficient funds (need $" << amount
<< ", have $" << balance << ")" << std::endl;
return false;
}
balance -= amount;
std::cout << " Withdrew $" << amount
<< " -> Balance: $" << balance << std::endl;
return true;
}
void printStatement() const {
std::cout << " +--------------------------+" << std::endl;
std::cout << " | Account #" << accountNumber << std::endl;
std::cout << " | Owner: " << owner << std::endl;
std::cout << " | Balance: $" << balance << std::endl;
std::cout << " +--------------------------+" << std::endl;
}
};
int BankAccount::nextAccountNumber = 1000;
// ============================================================
// 2. Temperature sensor with read-only external access
// ============================================================
class TemperatureSensor {
private:
double currentTemp;
double minTemp;
double maxTemp;
int readingCount;
public:
TemperatureSensor()
: currentTemp(0.0), minTemp(999.0), maxTemp(-999.0), readingCount(0) {}
// Only the sensor itself can record readings (simulating hardware input)
void recordReading(double temp) {
if (temp < -273.15) {
std::cout << " ERROR: temperature below absolute zero!" << std::endl;
return;
}
currentTemp = temp;
++readingCount;
if (temp < minTemp) minTemp = temp;
if (temp > maxTemp) maxTemp = temp;
}
// Public read-only access
double getCurrent() const { return currentTemp; }
double getMin() const { return minTemp; }
double getMax() const { return maxTemp; }
int getReadingCount() const { return readingCount; }
void printStats() const {
std::cout << " Readings: " << readingCount
<< ", Current: " << currentTemp
<< ", Min: " << minTemp
<< ", Max: " << maxTemp << std::endl;
}
};
// ============================================================
// 3. EmailValidator: internal logic hidden, clean interface
// ============================================================
class EmailValidator {
private:
char email[128];
bool valid;
// Private validation logic -- implementation can change
// without affecting the public interface
bool hasAtSign() const {
for (int i = 0; email[i] != '\0'; ++i) {
if (email[i] == '@') return true;
}
return false;
}
bool hasDot() const {
for (int i = 0; email[i] != '\0'; ++i) {
if (email[i] == '.') return true;
}
return false;
}
bool isLongEnough() const {
return std::strlen(email) >= 5; // a@b.c
}
void validate() {
valid = hasAtSign() && hasDot() && isLongEnough();
}
public:
EmailValidator(const char* e) : valid(false) {
std::strncpy(email, e, 127);
email[127] = '\0';
validate();
}
// Simple public interface
bool isValid() const { return valid; }
const char* getEmail() const { return email; }
void setEmail(const char* e) {
std::strncpy(email, e, 127);
email[127] = '\0';
validate(); // re-validate on change
}
};
int main() {
std::cout << "========================================" << std::endl;
std::cout << "1. BANK ACCOUNT (validated operations)" << std::endl;
std::cout << "========================================" << std::endl;
{
BankAccount acc("Alice", 1000.0);
acc.printStatement();
std::cout << std::endl;
acc.deposit(500.0);
acc.withdraw(200.0);
std::cout << "\n Attempting invalid operations:" << std::endl;
acc.deposit(-50.0); // rejected
acc.withdraw(5000.0); // rejected: insufficient funds
acc.withdraw(-10.0); // rejected
std::cout << std::endl;
acc.printStatement();
// acc.balance = 999999; // COMPILE ERROR: balance is private!
std::cout << "\n acc.balance = 999999; // COMPILE ERROR: private!" << std::endl;
}
std::cout << "\n========================================" << std::endl;
std::cout << "2. TEMPERATURE SENSOR (read-only stats)" << std::endl;
std::cout << "========================================" << std::endl;
{
TemperatureSensor sensor;
double readings[] = { 22.5, 23.1, 19.8, 25.0, 21.3 };
int count = 5;
for (int i = 0; i < count; ++i) {
sensor.recordReading(readings[i]);
}
// Invalid reading rejected
sensor.recordReading(-300.0);
sensor.printStats();
// sensor.currentTemp = 100; // COMPILE ERROR: private!
std::cout << " sensor.currentTemp = 100; // COMPILE ERROR: private!" << std::endl;
}
std::cout << "\n========================================" << std::endl;
std::cout << "3. EMAIL VALIDATOR (hidden logic)" << std::endl;
std::cout << "========================================" << std::endl;
{
const char* emails[] = {
"user@example.com",
"invalid",
"no@dot",
"a@b.c",
""
};
int count = 5;
for (int i = 0; i < count; ++i) {
EmailValidator ev(emails[i]);
std::cout << " \"" << ev.getEmail() << "\" -> "
<< (ev.isValid() ? "VALID" : "INVALID") << std::endl;
}
std::cout << "\n Changing email via setter:" << std::endl;
EmailValidator ev("bad");
std::cout << " \"" << ev.getEmail() << "\" -> "
<< (ev.isValid() ? "VALID" : "INVALID") << std::endl;
ev.setEmail("now.valid@email.com");
std::cout << " \"" << ev.getEmail() << "\" -> "
<< (ev.isValid() ? "VALID" : "INVALID") << std::endl;
}
std::cout << "\n========================================" << std::endl;
std::cout << "4. WHY ENCAPSULATION MATTERS" << std::endl;
std::cout << "========================================" << std::endl;
std::cout << " - Data integrity: setters enforce valid states" << std::endl;
std::cout << " - Flexibility: internal representation can change" << std::endl;
std::cout << " without breaking client code" << std::endl;
std::cout << " - Debugging: all changes go through known entry points" << std::endl;
std::cout << " - Security: sensitive data cannot be tampered with directly" << std::endl;
return 0;
}
// Expected output:
// ========================================
// 1. BANK ACCOUNT (validated operations)
// ========================================
// Account #1001 created for Alice
// +--------------------------+
// | Account #1001
// | Owner: Alice
// | Balance: $1000
// +--------------------------+
//
// Deposited $500 -> Balance: $1500
// Withdrew $200 -> Balance: $1300
//
// Attempting invalid operations:
// ERROR: deposit amount must be positive
// ERROR: insufficient funds (need $5000, have $1300)
// ERROR: withdrawal amount must be positive
//
// +--------------------------+
// | Account #1001
// | Owner: Alice
// | Balance: $1300
// +--------------------------+
//
// acc.balance = 999999; // COMPILE ERROR: private!
//
// ========================================
// 2. TEMPERATURE SENSOR (read-only stats)
// ========================================
// ERROR: temperature below absolute zero!
// Readings: 5, Current: 21.3, Min: 19.8, Max: 25
// sensor.currentTemp = 100; // COMPILE ERROR: private!
//
// ========================================
// 3. EMAIL VALIDATOR (hidden logic)
// ========================================
// "user@example.com" -> VALID
// "invalid" -> INVALID
// "no@dot" -> INVALID
// "a@b.c" -> VALID
// "" -> INVALID
// ...
//
// ========================================
// 4. WHY ENCAPSULATION MATTERS
// ========================================
// ...summary...
Run command
g++ -std=c++98 -Wall -Wextra -o example encapsulation.cpp