Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

C++ Object-Oriented Design: Encapsulation, Construction, and Operator Overloading

Tech 1

Encapsulation and Access Control

C++ encapsulation restricts direct access to internal state, exposing only validated interfaces. By default, class members are private, whereas struct members are public. Access specifiers (private, protected, public) define visibility boundaries, with protected becoming significant during inheritance hierarchies.

class InventoryItem {
    std::string sku;
    int quantity;
    
public:
    InventoryItem(std::string code, int qty) 
        : sku(code), quantity(qty) {}
    
    bool adjustStock(int delta) {
        if (quantity + delta >= 0) {
            quantity += delta;
            return true;
        }
        return false;
    }
    
    int getStock() const { return quantity; }
};

Data validation logic inside member functions prevents invalid states. External code cannot modify quantity directly, ensuring the inventory never becomes negative.

Construction and Destruction Lifecycle

Constructors initialize objects automatically upon instantiation. Destructors clean up resources when objects leave scope or are deleted.

class NetworkConnection {
    int socketFd;
    std::string endpoint;
    
public:
    NetworkConnection(std::string addr) : endpoint(addr), socketFd(-1) {
        socketFd = createSocket(addr);
    }
    
    ~NetworkConnection() {
        if (socketFd >= 0) close(socketFd);
    }
};

Automatic storage duration objects invoke destructors when exiting their block; static and global objects clean up after main() completes. Temporary (anonymous) objects execute constructors immediately and destructors at the end of the full expression:

PacketBuffer(4096);  // Anonymous object: constructs and destructs on this line

Copy Semantics

The compiler generates a default copy constructor performing member-wise copying. For pointer members, this creates shallow copies where multiple objects reference identical heap addresses.

class Document {
    char* content;
    size_t length;
    
public:
    Document(const char* text) {
        length = strlen(text);
        content = new char[length + 1];
        strcpy(content, text);
    }
    
    // Deep copy constructor
    Document(const Document& other) {
        length = other.length;
        content = new char[length + 1];
        memcpy(content, other.content, length + 1);
    }
    
    ~Document() { delete[] content; }
};

Deep copying allocates independent memory, preventing double-free errors during destruction. Copy construction triggers during value parameter passing and function returns:

void archiveDocument(Document doc);  // Copy constructor invoked here
Document fetchDocument();            // Return value optimization may elide copy

Member Initialization Order

When a class contains other class objects, construction follows declaration order, not initialization list order. Destruction proceeds in reverse:

class SystemModule {
    DatabaseConnection db;
    CacheLayer cache;
    // Construction: db first, then cache
    // Destruction: cache first, then db
};

Friend Functions and Classes

Friends bypass encapsulation for specific external functions or classes without exposing internals globally.

Global Friand Functions

class SecureWallet {
    double balance;
    int securityCode;
    
public:
    SecureWallet(double initial, int code) 
        : balance(initial), securityCode(code) {}
        
    friend bool verifyIntegrity(const SecureWallet& wallet, int auth);
};

bool verifyIntegrity(const SecureWallet& wallet, int auth) {
    return (auth == 9999) && (wallet.balance >= 0);
}

Friend Classes

When Auditor requires unrestricted access to SecureWallet:

class SecureWallet;  // Forward declaration

class Auditor {
public:
    void inspect(const SecureWallet& w);
};

class SecureWallet {
    double balance;
    friend class Auditor;
    
public:
    SecureWallet(double amount) : balance(amount) {}
};

void Auditor::inspect(const SecureWallet& w) {
    std::cout << "Balance: " << w.balance << std::endl;
}

Member Function Friends

Specific member functions of one class may become friends of another:

class Transaction;

class Account {
    double funds;
    friend void Transaction::commit(Account& acc);
};

Operator Overloading

Custom types utilize operators through explicit definitions, improving syntax clarity while maintaining type safety.

Arithmetic Operators

class Velocity {
    double vx, vy;
    
public:
    Velocity(double x, double y) : vx(x), vy(y) {}
    
    Velocity operator+(const Velocity& other) const {
        return Velocity(vx + other.vx, vy + other.vy);
    }
    
    friend Velocity operator*(double scalar, const Velocity& v) {
        return Velocity(v.vx * scalar, v.vy * scalar);
    }
};

Stream Insertion Operator

Stream operators require non-member implementation to position the stream object on the left:

class Telemetry {
    std::string sensorId;
    double reading;
    
public:
    Telemetry(std::string id, double val) 
        : sensorId(id), reading(val) {}
        
    friend std::ostream& operator<<(std::ostream& os, const Telemetry& t) {
        os << "[" << t.sensorId << "] " << t.reading << " units";
        return os;
    }
};

Increment Operators

Distinguish prefix and postfix using a dummy enteger parameter:

class StepCounter {
    unsigned steps;
    
public:
    StepCounter() : steps(0) {}
    
    // Prefix increment: return reference
    StepCounter& operator++() {
        ++steps;
        return *this;
    }
    
    // Postfix increment: return previous value
    StepCounter operator++(int) {
        StepCounter previous(*this);
        ++steps;
        return previous;
    }
};

Assignment Operators

Assignment requires handling self-assignment and resource management:

class ImageBuffer {
    uint8_t* pixels;
    size_t dimensions;
    
public:
    ImageBuffer& operator=(const ImageBuffer& other) {
        if (this != &other) {  // Self-assignment guard
            delete[] pixels;
            
            dimensions = other.dimensions;
            pixels = new uint8_t[dimensions];
            std::copy(other.pixels, other.pixels + dimensions, pixels);
        }
        return *this;
    }
};

Relational Operators

bool operator==(const Velocity& lhs, const Velocity& rhs) {
    return (lhs.vx == rhs.vx) && (lhs.vy == rhs.vy);
}

bool operator!=(const Velocity& lhs, const Velocity& rhs) {
    return !(lhs == rhs);
}

Function Call Operator

Functors overload operator() creating callable objects maintaining state:

class LinearMapper {
    double slope;
    double intercept;
    
public:
    LinearMapper(double m, double b) : slope(m), intercept(b) {}
    
    double operator()(double input) const {
        return slope * input + intercept;
    }
};

// Usage
LinearMapper convert(9.0/5.0, 32);  // Celsius to Fahrenheit
double tempF = convert(100.0);      // Returns 212.0

// Anonymous functor
int result = LinearMapper(2, 10)(5);  // Returns 20, object destroyed immediately
Tags: C++OOP

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.