క్లాసెస్, ఆబ్జెక్ట్స్ & Encapsulation

🌐 Modern C++ (C++20/C++17) 🟢 Chapter 13 of 20 📂 Phase 04: ఆబ్జెక్ట్ ఓరియెంటెడ్ OOP 📅 2026 Edition
📌 Covered in this chapter: Class vs Struct · Access Specifiers (public, private, protected) · Getters & Setters · this పాయింటర్ · const Member Functions

కంప్యూటర్ ప్రోగ్రామింగ్ చరిత్రలో అతిపెద్ద మైలురాయి: ఆబ్జెక్ట్ ఓరియెంటెడ్ ప్రోగ్రామింగ్ (Object-Oriented Programming - OOP). సాంప్రదాయ ప్రొసీజరల్ భాషల్లో (C వంటివి) డేటా వేరుగా, ఆ డేటాపై పనిచేసే ఫంక్షన్లు వేరుగా ఉండేవి. దీనివల్ల ప్రాజెక్ట్ పరిమాణం పెరిగేకొద్దీ కోడ్ నియంత్రణ కోల్పోయి భారీ గందరగోళం ఏర్పడేది.

ఈ సమస్యకు పరిష్కారంగానే C++ సృష్టికర్త Bjarne Stroustrup "C with Classes" అనే కాన్సెప్ట్‌తో C++ ను అభివృద్ధి చేశారు. నిజ జీవిత వస్తువులైన కార్లు, బ్యాంక్ ఖాతాలు, యూజర్లు, గేమ్ క్యారెక్టర్లను ప్రోగ్రామ్‌లో మోడల్ చేయడానికి క్లాసెస్ (Classes) మరియు ఆబ్జెక్ట్స్ (Objects) పునాదిగా నిలుస్తాయి. అంతేకాకుండా అనధికారిక వ్యక్తులు మన డేటాను తారుమారు చేయకుండా కాపాడే అత్యంత శక్తివంతమైన రక్షణ కవచమే డేటా ఎన్‌క్యాప్సులేషన్ (Encapsulation).

ఈ లోతైన మాస్టర్‌క్లాస్‌లో మనం Class vs Struct అంతర్గత తేడాలు, Access Specifiers (public, private, protected), Getters & Setters ద్వారా Data Invariants ను కాపాడటం, this పాయింటర్ మెకానిక్స్, const మెంబర్ ఫంక్షన్లు, static క్లాస్ లెవెల్ డేటా, మరియు పూర్తి స్థాయి "Enterprise Core Banking Account & Ledger Engine" ప్రాజెక్ట్‌ను లైవ్‌గా నిర్మించి ప్రావీణ్యం సంపాదిద్దాం!

1 ప్రొసీజరల్ వర్సెస్ ఆబ్జెక్ట్-ఓరియెంటెడ్ ప్రోగ్రామింగ్ (The OOP Paradigm Shift)

సాఫ్ట్‌వేర్ నిర్మాణ శైలిలో రెండు ప్రధాన ఆలోచనా విధానాలు (Paradigms) ఉన్నాయి:

  • ప్రొసీజరల్ ప్రోగ్రామింగ్ (Procedural Programming - C, Pascal): ఇక్కడ ప్రాధాన్యత "పని ఎలా జరగాలి?" (Functions & Steps) అనే దానిపై ఉంటుంది. డేటా అంతా గ్లోబల్ వేరియబుల్స్ లేదా స్ట్రక్చర్లలో బహిరంగంగా ఉంటుంది. ఎవరైనా, ఎక్కడి నుంచైనా ఆ డేటాను నేరుగా మార్చేయవచ్చు. ప్రాజెక్ట్ 10 లక్షల లైన్లకు చేరినప్పుడు ఏ ఫంక్షన్ డేటాను పాడుచేసిందో కనిపెట్టడం అసాధ్యం అవుతుంది.
  • ఆబ్జెక్ట్ ఓరియెంటెడ్ ప్రోగ్రామింగ్ (OOP - C++, Java, C#): ఇక్కడ ప్రాధాన్యత "ఎవరు పని చేస్తున్నారు? డేటా ఎవరి వద్ద సురక్షితంగా ఉంది?" (Objects & Data Ownership) అనే దానిపై ఉంటుంది. డేటాను మరియు ఆ డేటాపై పనిచేసే ఫంక్షన్లను ఒకే యూనిట్ (Class) లోపల బంధిస్తాం.
[The 4 Pillars of Object-Oriented Programming]
1. Encapsulation (ఎన్‌క్యాప్సులేషన్): Binding Data + Functions into a single capsule & Information Hiding.
2. Abstraction (అబ్‌స్ట్రాక్షన్): Exposing only the essential interface while hiding internal implementation details.
3. Inheritance (ఇన్హెరిటెన్స్): Code reusability by creating specialized classes from base classes.
4. Polymorphism (పాలిమార్ఫిజమ్): One single interface with multiple dynamic implementations (Virtual functions).

2 క్లాస్ మరియు ఆబ్జెక్ట్ అంటే ఏమిటి? (Blueprint vs Instance)

క్లాస్ మరియు ఆబ్జెక్ట్ మధ్య తేడాను అర్థం చేసుకోవడానికి ఒక రియల్ వరల్డ్ ఉదాహరణ చూద్దాం:

  • క్లాస్ (Class): ఒక ఇంటిని నిర్మించడానికి ఇంజనీర్ గీసిన బ్లూప్రింట్ లేదా మ్యాప్ (Blueprint) వంటిది. బ్లూప్రింట్ అనేది కేవలం కాగితం మీద డిజైన్ మాత్రమే; అది నిజంగా భూమిపై స్థలాన్ని ఆక్రమించదు.
  • ఆబ్జెక్ట్ (Object): ఆ బ్లూప్రింట్ ఆధారంగా ఇటుకలు, సిమెంట్ ఉపయోగించి భూమిపై నిర్మించిన నిజమైన ఇల్లు (Real House). అది నిజమైన స్థలాన్ని ఆక్రమిస్తుంది. ఒకే బ్లూప్రింట్ ఆధారంగా మనం 100 వేర్వేరు ఇళ్లను నిర్మించవచ్చు!

కంప్యూటర్ పరిభాషలో: క్లాస్ అనేది ఒక యూజర్-డిఫైన్డ్ డేటా టైప్; మరియు ఆబ్జెక్ట్ అనేది RAM లో మెమరీ కేటాయించబడిన ఆ క్లాస్ యొక్క ఉనికి (Instance).

class_object_basics.cpp
#include <iostream>
#include <string>

// క్లాస్ డిక్లరేషన్ (బ్లూప్రింట్)
class ElectricCar {
public:
    std::string model;
    int batteryCapacity; // kWh
    int speed;

    void accelerate(int increase) {
        speed += increase;
        std::cout << model << " వేగం " << speed << " km/h కి పెరిగింది!\n";
    }
}; // ⚠️ క్లాస్ చివర సెమికోలన్ (;) తప్పనిసరి!

int main() {
    // ఆబ్జెక్ట్‌ల సృష్టి (Instances in RAM)
    ElectricCar car1;
    car1.model = "Tata Nexon EV";
    car1.batteryCapacity = 40;
    car1.speed = 0;

    ElectricCar car2;
    car2.model = "Tesla Model 3";
    car2.batteryCapacity = 75;
    car2.speed = 0;

    std::cout << "car1 మోడల్: " << car1.model << " (RAM అడ్రస్: " << &car1 << ")\n";
    std::cout << "car2 మోడల్: " << car2.model << " (RAM అడ్రస్: " << &car2 << ")\n";

    car1.accelerate(40);
    car2.accelerate(80);
    return 0;
}

3 C++ లో class వర్సెస్ struct లోతైన వ్యత్యాసం

చాలా మంది బిగినర్స్ struct అనేది డేటా కోసమేనని, class ఫంక్షన్ల కోసమని పొరబడుతుంటారు. కానీ C++ లో struct మరియు class రెండూ సమానమైన శక్తులను కలిగి ఉంటాయి — రెంటిలోనూ మెంబర్ ఫంక్షన్లు, కన్‌స్ట్రక్టర్లు, ఇన్హెరిటెన్స్ అన్నీ ఉంటాయి!

అయితే వాటి మధ్య ఉన్న ఏకైక వ్యత్యాసం ఏమిటి?

Default Access Specifier:
• struct లో మీరు ఏమీ పేర్కొనకపోతే అన్ని మెంబర్లు డిఫాల్ట్‌గా public అవుతాయి.
• class లో మీరు ఏమీ పేర్కొనకపోతే అన్ని మెంబర్లు డిఫాల్ట్‌గా private అవుతాయి!
ఫీచర్ struct class
డిఫాల్ట్ యాక్సెస్ public (అందరికీ ఓపెన్) private (బయటి నుండి దాచబడుతుంది)
డిఫాల్ట్ ఇన్హెరిటెన్స్ public inheritance private inheritance
ఇండస్ట్రీ కన్వెన్షన్ POD (Plain Old Data) లేదా కేవలం పబ్లిక్ డేటా ఫీల్డ్స్ కలెక్షన్ ఎన్‌క్యాప్సులేషన్, ప్రైవేట్ డేటా మరియు ఇన్వేరియంట్స్ ఉన్న కాంప్లెక్స్ బిజినెస్ లాజిక్

4 Access Specifiers: public, private, మరియు protected

క్లాస్ లోపల ఉన్న వేరియబుల్స్ మరియు ఫంక్షన్లను ఎవరు యాక్సెస్ చేయవచ్చో నియంత్రించడానికి C++ మూడు Access Specifiers ను అందిస్తుంది:

  1. public: బహిరంగ ప్రవేశం. క్లాస్ లోపల మరియు క్లాస్ వెలుపల ప్రోగ్రామ్‌లోని ఏ ఫంక్షన్ అయినా వీటిని నేరుగా యాక్సెస్ చేయవచ్చు.
  2. private: అంతర్గత ప్రవేశం (Secret). కేవలం ఆ క్లాస్ లోపల ఉన్న మెంబర్ ఫంక్షన్లు మాత్రమే వీటిని తాకగలవు. క్లాస్ వెలుపల నుండి యాక్సెస్ చేయడానికి ప్రయత్నిస్తే కంపైలేషన్ ఎర్రర్ వస్తుంది.
  3. protected: వారసత్వ ప్రవేశం. ఆ క్లాస్ మరియు దాని నుండి పుట్టిన చైల్డ్ క్లాసులు (Derived Classes) మాత్రమే యాక్సెస్ చేయగలవు. బాహ్య ప్రపంచానికి ఇది ప్రైవేట్ వలె రక్షించబడుతుంది.
access_specifiers_demo.cpp
#include <iostream>
#include <string>

class BankVault {
private:
    double totalCash; // ప్రైవేట్ - బయట వారు నేరుగా మార్చలేరు!

public:
    std::string branchName; // పబ్లిక్ - అందరూ చూడవచ్చు

    void deposit(double amount) {
        if (amount > 0) {
            totalCash += amount;
            std::cout << "₹ " << amount << " జమ చేయబడింది.\n";
        }
    }

    void showBalance() {
        std::cout << branchName << " మొత్తం నగదు: ₹ " << totalCash << "\n";
    }
};

int main() {
    BankVault vault;
    vault.branchName = "Hyderabad Main Branch"; // సవ్యమైనది (public)

    // vault.totalCash = 100000000; // ❌ కంపైలర్ ఎర్రర్! 'totalCash' is private!
    vault.deposit(50000);          // సవ్యమైనది! పబ్లిక్ మెథడ్ ద్వారా మాత్రమే డిపాజిట్ సాధ్యం
    vault.showBalance();
    return 0;
}

5 డేటా ఎన్‌క్యాప్సులేషన్ (Data Encapsulation) & Getters / Setters

ఎన్‌క్యాప్సులేషన్ అంటే ఏమిటి? డేటాను (State) మరియు ఆ డేటాపై పనిచేసే ఫంక్షన్లను (Behavior) ఒకే క్లాస్ క్యాప్సూల్‌లో బంధించి, సున్నితమైన డేటాను private గా దాచిపెట్టడాన్నే ఎన్‌క్యాప్సులేషన్ అంటాం.

డేటాను ప్రైవేట్‌గా ఎందుకు ఉంచాలి? ఆలోచించండి: ఒక బ్యాంక్ అకౌంట్‌లో balance అనేది పబ్లిక్ అయితే, ఎవరైనా పొరపాటున acc.balance = -50000; అని రాయవచ్చు! లేదా ఒక మనిషి వయస్సు person.age = -15; అని మార్చేయవచ్చు.

దీనిని నివారించడానికి మనం డేటా మెంబర్లను private గా ఉంచి, వాటిని చదవడానికి Getters మరియు సరైన నిబంధనలను (Validation Logic) తనిఖీ చేసి మార్చడానికి Setters ను ఉపయోగిస్తాం.

encapsulation_getters_setters.cpp
#include <iostream>
#include <string>

class Employee {
private:
    std::string empName;
    double monthlySalary;

public:
    // Getter ఫంక్షన్ (Read-Only)
    std::string getName() const {
        return empName;
    }

    double getSalary() const {
        return monthlySalary;
    }

    // Setter ఫంక్షన్ విత్ బిజినెస్ వాలిడేషన్
    void setName(const std::string& name) {
        if (!name.empty()) {
            empName = name;
        }
    }

    void setSalary(double salary) {
        if (salary >= 15000.0) { // కనీస వేతన రూల్
            monthlySalary = salary;
        } else {
            std::cout << "⚠️ హెచ్చరిక: వేతనం కనీసం ₹ 15,000 ఉండాలి! తిరస్కరించబడింది.\n";
        }
    }
};

int main() {
    Employee emp;
    emp.setName("Suresh Raina");
    emp.setSalary(50000.0);

    std::cout << "ఉద్యోగి: " << emp.getName() << " | జీతం: ₹ " << emp.getSalary() << "\n";

    emp.setSalary(-500); // వాలిడేషన్ ఫెయిల్ అవుతుంది, డేటా కరప్ట్ కాదు!
    return 0;
}

6 this పాయింటర్ అంతర్గత మెకానిక్స్ (The Implicit Instance Pointer)

C++ లో ప్రతి నాన్-స్టాటిక్ మెంబర్ ఫంక్షన్ లోపల కంపైలర్ అదృశ్యంగా ఒక ప్రత్యేకమైన పాయింటర్‌ను పాస్ చేస్తుంది. దాని పేరే this పాయింటర్.

this పాయింటర్ లక్షణాలు:

  • ఇది ఏ ఆబ్జెక్ట్ ద్వారా అయితే ఫంక్షన్ పిలువబడిందో, ఆ ప్రస్తుత ఆబ్జెక్ట్ యొక్క ఖచ్చితమైన మెమరీ చిరునామాను కలిగి ఉంటుంది (Type: ClassName* const this).
  • పేర్ల గందరగోళం (Name Shadowing) నివారణ: ఫంక్షన్ పారామీటర్ పేరు మరియు క్లాస్ మెంబర్ వేరియబుల్ పేరు ఒకటే అయినప్పుడు, క్లాస్ వేరియబుల్‌ను స్పష్టంగా సూచించడానికి this->variable = variable; అని రాస్తాం.
  • మెథడ్ చైనింగ్ (Method Chaining / Fluent API): ఒక ఫంక్షన్ నుండి ప్రస్తుత ఆబ్జెక్ట్‌ను రిటర్న్ చేయడానికి return *this; వాడతాం. దీనివల్ల obj.setA(10).setB(20).execute(); వంటి అందమైన ఫ్లూయెంట్ కోడ్ రాయవచ్చు.
this_pointer_chaining.cpp
#include <iostream>

class OrderBuilder {
private:
    int itemsCount = 0;
    double totalPrice = 0.0;

public:
    // Method Chaining కొరకు Reference to *this రిటర్న్ చేస్తున్నాం
    OrderBuilder& addItem(double price) {
        this->itemsCount++; // this-> ద్వారా మెంబర్ వేరియబుల్ యాక్సెస్
        this->totalPrice += price;
        return *this; // ప్రస్తుత ఆబ్జెక్ట్ రిఫరెన్స్ రిటర్న్
    }

    OrderBuilder& applyDiscount(double discountPercentage) {
        this->totalPrice -= (this->totalPrice * (discountPercentage / 100.0));
        return *this;
    }

    void printSummary() const {
        std::cout << "ఆర్డర్ సారాంశం: " << this->itemsCount << " వస్తువులు | మొత్తం బిల్: ₹ " << this->totalPrice << "\n";
        std::cout << "ఆబ్జెక్ట్ మెమరీ అడ్రస్ (this): " << this << "\n";
    }
};

int main() {
    OrderBuilder order;
    // ఫ్లూయెంట్ మెథడ్ చైనింగ్ డెమో!
    order.addItem(1200.0)
         .addItem(800.0)
         .addItem(500.0)
         .applyDiscount(10.0)
         .printSummary();

    return 0;
}

7 const మెంబర్ ఫంక్షన్లు (Const Correctness in Classes)

ఒక మెంబర్ ఫంక్షన్ కేవలం ఆబ్జెక్ట్ లోపల ఉన్న డేటాను చదవడానికి (Read-Only) మాత్రమే ఉద్దేశించబడినప్పుడు, ఆ ఫంక్షన్ డిక్లరేషన్ చివర const కీవర్డ్ చేర్చడం C++ లో ఒక సువర్ణ నియమం.

double getBalance() const; // ఈ ఫంక్షన్ ఏ వేరియబుల్ నూ సవరించదు అని కంపైలర్ ప్రామిస్!

దీనివల్ల ప్రయోజనాలు ఏమిటి?

  1. పొరపాటున ఆ ఫంక్షన్ లోపల ఏదైనా వేరియబుల్‌ను మార్చడానికి ప్రయత్నిస్తే కంపైలర్ వెంటనే లోపాన్ని పట్టిస్తుంది.
  2. మనం ఒక ఆబ్జెక్ట్‌ను const MyClass& obj రూపంలో జీరో-కాపీగా ఫంక్షన్లకు పాస్ చేసినప్పుడు, ఆ const ఆబ్జెక్ట్ కేవలం const మెంబర్ ఫంక్షన్లను మాత్రమే పిలవగలదు! నాన్-కాన్స్ట్ ఫంక్షన్లను పిలిస్తే కంపైలేషన్ ఎర్రర్ వస్తుంది.
const_member_functions.cpp
#include <iostream>

class SensorMonitor {
private:
    double temperature;
    mutable int accessCounter = 0; // mutable: const ఫంక్షన్ లోనూ మార్చవచ్చు!

public:
    void setTemperature(double temp) {
        temperature = temp;
    }

    // const మెంబర్ ఫంక్షన్
    double readTemperature() const {
        accessCounter++; // mutable వేరియబుల్ కాబట్టి మార్చడం అనుమతించబడుతుంది (లాగింగ్ కొరకు)
        // temperature += 1.0; // ❌ కంపైలర్ ఎర్రర్! const ఫంక్షన్ లో మెంబర్లను మార్చలేము!
        return temperature;
    }

    int getAccessCount() const { return accessCounter; }
};

void inspectSensor(const SensorMonitor& sensor) {
    // sensor అనేది const reference, కాబట్టి readTemperature() మాత్రమే కాల్ అవుతుంది
    std::cout << "సెన్సార్ ఉష్ణోగ్రత రీడింగ్: " << sensor.readTemperature() << " °C\n";
}

int main() {
    SensorMonitor sm;
    sm.setTemperature(36.5);
    inspectSensor(sm);
    return 0;
}

8 స్టాటిక్ మెంబర్లు: static వేరియబుల్స్ & static ఫంక్షన్లు

సాధారణంగా క్లాస్ లోపల ఉండే వేరియబుల్స్ ప్రతి ఆబ్జెక్ట్‌కు విడివిడిగా మెమరీలో సృష్టించబడతాయి (ఉదాహరణకు 10 మంది కస్టమర్ ఆబ్జెక్టులు ఉంటే 10 వేర్వేరు balance లు ఉంటాయి).

కానీ క్లాస్ మొత్తానికి కలిపి ఉమ్మడిగా ఒకే ఒక్క వేరియబుల్ ఉండాలనుకుంటే మనం static కీవర్డ్‌ను ఉపయోగిస్తాం!

  • Static Member Variables: ఆబ్జెక్ట్‌తో సంబంధం లేకుండా క్లాస్ మొత్తానికి గ్లోబల్ మెమరీలో ఒకే కాపీ ఉంటుంది. మొత్తం ఆబ్జెక్టుల సంఖ్యను లెక్కించడానికి, లేదా షేర్డ్ కాన్ఫిగరేషన్‌ను ఉంచడానికి ఇది వాడతాం.
  • Static Member Functions: వీటిని పిలవడానికి ఏ ఆబ్జెక్ట్ అవసరం లేదు! నేరుగా క్లాస్ పేరుతో పిలవవచ్చు (ClassName::staticMethod()). వీటికి this పాయింటర్ ఉండదు, అందువల్ల ఇవి కేవలం ఇతర స్టాటిక్ వేరియబుల్స్‌ను మాత్రమే యాక్సెస్ చేయగలవు.
static_members_demo.cpp
#include <iostream>
#include <string>

class UserAccount {
private:
    std::string username;

    // C++17 inline static ద్వారా క్లాస్ లోపలే డైరెక్ట్ ఇనిషియలైజేషన్!
    inline static int totalActiveUsers = 0;

public:
    UserAccount(std::string name) : username(name) {
        totalActiveUsers++;
        std::cout << "  [యూజర్ క్రియేట్ చేయబడ్డాడు]: " << username << "\n";
    }

    ~UserAccount() {
        totalActiveUsers--;
        std::cout << "  [యూజర్ తొలగించబడ్డాడు]: " << username << "\n";
    }

    // Static మెంబర్ ఫంక్షన్
    static int getActiveUserCount() {
        // username = "test"; // ❌ ఎర్రర్! static ఫంక్షన్ లో non-static వేరియబుల్స్ వాడలేము!
        return totalActiveUsers;
    }
};

int main() {
    std::cout << "ప్రారంభ యూజర్ల కౌంట్: " << UserAccount::getActiveUserCount() << "\n";

    UserAccount u1("Chaitanya");
    UserAccount u2("Bhavana");
    std::cout << "ప్రస్తుత యూజర్ల కౌంట్: " << UserAccount::getActiveUserCount() << "\n";

    {
        UserAccount u3("Divya");
        std::cout << "స్కోప్ లోపల యూజర్ల కౌంట్: " << UserAccount::getActiveUserCount() << "\n";
    } // u3 డిస్ట్రక్ట్ అవుతుంది

    std::cout << "స్కోప్ వెలుపల యూజర్ల కౌంట్: " << UserAccount::getActiveUserCount() << "\n";
    return 0;
}

9 క్లాస్ డెఫినిషన్ ఇన్సైడ్ వర్సెస్ అవుట్‌సైడ్ (Scope Resolution ::)

ప్రొఫెషనల్ ఎంటర్‌ప్రైజ్ C++ కోడ్‌బేస్‌లలో క్లాస్ లోపలే అన్ని ఫంక్షన్ల కోడ్‌ను రాయడం అస్సలు మంచి పద్ధతి కాదు. దానివల్ల క్లాస్ హెడర్ ఫైల్ భారీగా మారి చదవడానికి కష్టమవుతుంది.

అందువల్ల క్లాస్ లోపల కేవలం ఫంక్షన్ ప్రోటోటైప్స్ (డిక్లరేషన్స్) మాత్రమే రాసి, వాటి పూర్తి ఇంప్లిమెంటేషన్‌ను క్లాస్ వెలుపల Scope Resolution Operator (::) ద్వారా రాస్తాం.

scope_resolution_demo.cpp
#include <iostream>

class Calculator {
private:
    double lastResult;

public:
    Calculator(); // కన్‌స్ట్రక్టర్ డిక్లరేషన్
    double add(double a, double b); // మెంబర్ ఫంక్షన్ డిక్లరేషన్
    void printHistory() const;
};

// క్లాస్ వెలుపల Scope Resolution Operator (::) తో బాడీ రాయడం:
Calculator::Calculator() : lastResult(0.0) {}

double Calculator::add(double a, double b) {
    lastResult = a + b;
    return lastResult;
}

void Calculator::printHistory() const {
    std::cout << "గతంలో గణించిన తాజా ఫలితం: " << lastResult << "\n";
}

int main() {
    Calculator calc;
    std::cout << "సంకలనం (15 + 25): " << calc.add(15, 25) << "\n";
    calc.printHistory();
    return 0;
}

10 క్లాస్ ఆబ్జెక్ట్ సైజ్, మెమరీ ప్యాడింగ్ & ఎంప్టీ క్లాస్

ఒక క్లాస్ ఆబ్జెక్ట్ RAM లో ఎంత మెమరీని ఆక్రమిస్తుంది?

  • మెంబర్ ఫంక్షన్లు మెమరీని ఆక్రమించవు: ఒక క్లాస్‌లో 100 ఫంక్షన్లు ఉన్నా, అవి కోడ్ సెగ్మెంట్ (Text Segment) లో ఉంటాయి తప్ప ఆబ్జెక్ట్ సైజ్‌ను పెంచవు! ఆబ్జెక్ట్ సైజ్ కేవలం దాని లోపల ఉన్న నాన్-స్టాటిక్ వేరియబుల్స్ పై మాత్రమే ఆధారపడి ఉంటుంది.
  • ఎంప్టీ క్లాస్ సైజ్ (Empty Class Size): ఏ వేరియబుల్స్ లేని ఒక ఖాళీ క్లాస్ class Dummy {}; సైజ్ ఎంత ఉంటుంది? సమాధానం: ఖచ్చితంగా 1 బైట్! ఎందుకంటే C++ ఆర్కిటెక్చర్‌లో ప్రతి ఆబ్జెక్ట్‌కు ఒక ప్రత్యేకమైన మెమరీ అడ్రస్ ఉండాలి. సైజ్ 0 అయితే రెండు వేర్వేరు ఆబ్జెక్టులు ఒకే మెమరీ అడ్రస్‌ను పంచుకునే వైరుధ్యం వస్తుంది.
  • మెమరీ ప్యాడింగ్ (Padding): CPU 64-bit బౌండరీలపై వేగంగా చదవడానికి వేరియబుల్స్ మధ్య ఖాళీ బైట్లను (Padding Bytes) చేరుస్తుంది.
class_memory_size.cpp
#include <iostream>

class EmptyClass {};

class StructuredData {
    char a;    // 1 Byte + 3 Bytes Padding
    int b;     // 4 Bytes
    double c;  // 8 Bytes
};

int main() {
    std::cout << "sizeof(EmptyClass):    " << sizeof(EmptyClass) << " Byte (ప్రత్యేక అడ్రస్ కొరకు)\n";
    std::cout << "sizeof(StructuredData): " << sizeof(StructuredData) << " Bytes (విత్ CPU Alignment Padding)\n";
    return 0;
}

11 సాధారణ OOP డిజైన్ తప్పులు & బెస్ట్ ప్రాక్టీసెస్

  1. అన్ని వేరియబుల్స్‌ను పబ్లిక్‌గా ఉంచడం: దీనివల్ల ఎవరైనా ఏ నిబంధన లేకుండా డేటాను మార్చేయవచ్చు. ఎల్లప్పుడూ మెంబర్ వేరియబుల్స్‌ను private గా ఉంచండి.
  2. గుడ్డిగా ప్రతిదానికీ Getters & Setters రాయడం: క్లాస్ అంటే కేవలం డేటా హోల్డర్ కాదు. దానికి బిహేవియర్ ఉండాలి (ఉదాహరణకు acc.setBalance(acc.getBalance() + 500) బదులుగా acc.deposit(500) అని పిలవాలి).
  3. Const Correctness విస్మరించడం: డేటాను సవరించని ఏ మెథడ్‌కైనా const రాయకపోతే, ఆ క్లాస్ ఆబ్జెక్టులను వేరే లైబ్రరీలలో const& గా ఉపయోగించడం అసాధ్యం అవుతుంది.

12 రియల్-వరల్డ్ ప్రాజెక్ట్: Enterprise Core Banking Account & Ledger Engine

నిజ జీవితంలో HDFC లేదా State Bank of India వంటి బ్యాంకింగ్ సిస్టమ్స్ లోపల ఖాతాదారుల నగదు లావాదేవీలు అత్యంత కట్టుదిట్టమైన ఎన్‌క్యాప్సులేషన్ రక్షణలో నడుస్తాయి. పిన్ ధృవీకరణ లేకుండా నగదు తీయడం కుదరదు, కనీస నిల్వ (Minimum Balance) తగ్గకూడదు, మరియు బ్రాంచ్ వ్యాప్తంగా మొత్తం టర్నోవర్‌ను స్టాటిక్ లెడ్జర్ ద్వారా ట్రాక్ చేయాలి.

ఈ సమగ్ర ప్రాజెక్ట్‌లో మనం ప్రైవేట్ స్టేట్, సెక్యూర్ పిన్ ధృవీకరణ, మెథడ్ చైనింగ్, మరియు క్లాస్-లెవల్ స్టాటిక్ ఆడిట్‌తో కూడిన ఎంటర్‌ప్రైజ్ కోర్ బ్యాంకింగ్ లెడ్జర్ ఇంజిన్ ను నిర్మిస్తున్నాం:

EnterpriseCoreBankingEngine.cpp
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>

class BankAccount {
private:
    std::string accountNumber;
    std::string accountHolder;
    double balance;
    int securityPin;
    std::vector<std::string> passbookEntries;

    // క్లాస్-లెవల్ స్టాటిక్ ఆడిట్ వేరియబుల్స్
    inline static int totalAccountsCreated = 0;
    inline static double totalBankDeposits = 0.0;

public:
    BankAccount(std::string accNo, std::string holder, double initialDeposit, int pin)
        : accountNumber(accNo), accountHolder(holder), balance(initialDeposit), securityPin(pin) {
        totalAccountsCreated++;
        totalBankDeposits += initialDeposit;
        passbookEntries.push_back("ప్రారంభ ఖాతా డిపాజిట్: ₹ " + std::to_string(initialDeposit));
    }

    // Method Chaining డిపాజిట్ ఫంక్షన్
    BankAccount& deposit(double amount) {
        if (amount <= 0) {
            std::cout << "❌ డిపాజిట్ తిరస్కరించబడింది: మొత్తం తప్పనిసరిగా ధనాత్మకంగా ఉండాలి.\n";
            return *this;
        }
        balance += amount;
        totalBankDeposits += amount;
        passbookEntries.push_back("జమ (Deposit): +₹ " + std::to_string(amount));
        std::cout << "✅ [జమ సఫలం] " << accountHolder << " ఖాతాలో ₹ " << amount << " జమ చేయబడింది.\n";
        return *this;
    }

    // సెక్యూర్ విత్‌డ్రాయల్ ఫంక్షన్ (విత్ పిన్ వెరిఫికేషన్ & మినిమమ్ బ్యాలెన్స్ చెక్)
    bool withdraw(double amount, int pin) {
        if (pin != securityPin) {
            std::cout << "🚨 [భద్రతా హెచ్చరిక] తప్పుడు సెక్యూరిటీ పిన్! విత్‌డ్రాయల్ నిలిపివేయబడింది.\n";
            return false;
        }
        const double MIN_BALANCE = 1000.0;
        if (balance - amount < MIN_BALANCE) {
            std::cout << "⚠️ [లావాదేవీ రద్దు] ఖాతాలో కనీస బ్యాలెన్స్ ₹ 1,000 తప్పనిసరి. ప్రస్తుత నిల్వ: ₹ " << balance << "\n";
            return false;
        }

        balance -= amount;
        totalBankDeposits -= amount;
        passbookEntries.push_back("విత్‌డ్రాయల్ (Withdrawal): -₹ " + std::to_string(amount));
        std::cout << "💸 [నగదు ఉపసంహరణ సఫలం] ₹ " << amount << " డ్రా చేయబడింది. మిగిలిన బ్యాలెన్స్: ₹ " << balance << "\n";
        return true;
    }

    // Read-Only const ఫంక్షన్
    void printPassbook() const {
        std::cout << "\n--------------------------------------------------------------\n";
        std::cout << "📖 [అధికారిక పాస్‌బుక్ స్టేట్‌మెంట్ - " << accountHolder << "]\n";
        std::cout << "ఖాతా సంఖ్య: " << accountNumber << " | ప్రస్తుత నిల్వ: ₹ " << std::fixed << std::setprecision(2) << balance << "\n";
        std::cout << "లావాదేవీల రికార్డు:\n";
        for (const auto& entry : passbookEntries) {
            std::cout << "  • " << entry << "\n";
        }
        std::cout << "--------------------------------------------------------------\n";
    }

    // Static క్లాస్ ఆడిట్ రిపోర్ట్
    static void generateBankTurnoverReport() {
        std::cout << "\n==============================================================\n";
        std::cout << "🏦 [GLOBAL CORE BANKING AUDIT & TURNOVER REPORT]\n";
        std::cout << "మొత్తం యాక్టివ్ ఖాతాలు     : " << totalAccountsCreated << "\n";
        std::cout << "మొత్తం బ్యాంక్ డిపాజిట్ నిల్వ: ₹ " << std::fixed << std::setprecision(2) << totalBankDeposits << "\n";
        std::cout << "==============================================================\n";
    }
};

int main() {
    std::cout << "==============================================================\n";
    std::cout << "🏦 [ENTERPRISE CORE BANKING LEDGER SYSTEM RUNNING]\n";
    std::cout << "==============================================================\n";

    BankAccount acc1("ACC_987654321", "రమేష్ వర్మ", 25000.0, 4321);
    BankAccount acc2("ACC_123456789", "సునీత రావు", 50000.0, 9988);

    // Method Chaining ద్వారా వరుస డిపాజిట్లు
    acc1.deposit(10000.0).deposit(5000.0);

    // విత్‌డ్రాయల్ ప్రయత్నాలు
    acc1.withdraw(5000.0, 4321); // సరైన పిన్
    acc1.withdraw(10000.0, 1111); // తప్పుడు పిన్ - సెక్యూరిటీ బ్లాక్!

    acc2.deposit(15000.0);
    acc2.withdraw(60000.0, 9988); // కనీస బ్యాలెన్స్ రూల్ ఫెయిల్

    // స్టేట్‌మెంట్లు ప్రింట్ చేయడం
    acc1.printPassbook();
    acc2.printPassbook();

    // గ్లోబల్ స్టాటిక్ ఆడిట్ రిపోర్ట్
    BankAccount::generateBankTurnoverReport();

    return 0;
}

13 సారాంశం & ఇంటరాక్టివ్ క్విజ్ (Summary & Self-Check Quizzes)

📌 ఈ అధ్యాయంలో నేర్చుకున్న ప్రధాన అంశాలు:

  • Class vs Object: క్లాస్ అనేది బ్లూప్రింట్ (యూజర్ డిఫైన్డ్ టైప్); ఆబ్జెక్ట్ అనేది RAM లో మెమరీ కలిగిన నిజమైన ఉనికి.
  • Class vs Struct: C++ లో రెండింటికీ ఒకే సామర్థ్యాలు ఉన్నాయి. ఏకైక తేడా: struct లో డిఫాల్ట్‌గా అన్ని public, class లో డిఫాల్ట్‌గా అన్ని private.
  • Access Specifiers: public అందరికీ లభిస్తుంది, private కేవలం క్లాస్ లోపలే ఉంటుంది, protected వారసత్వ క్లాసులకు మాత్రమే అందుబాటులో ఉంటుంది.
  • Encapsulation: డేటాను ప్రైవేట్‌గా దాచిపెట్టి, Getters/Setters మరియు బిహేవియర్ మెథడ్స్ ద్వారా మాత్రమే నియంత్రిత ప్రాప్యత కల్పించడం.
  • this Pointer: ప్రస్తుత ఆబ్జెక్ట్ మెమరీ అడ్రస్‌ను సూచించే ఇంప్లిసిట్ పాయింటర్. నేమ్ షాడోయింగ్ నివారణకు మరియు మెథడ్ చైనింగ్‌కు తప్పనిసరి.
  • const Member Functions: ఆబ్జెక్ట్ స్టేట్‌ను మార్చని రీడ్-ఓన్లీ ఫంక్షన్లు. const రిఫరెన్సులతో పనిచేయడానికి ఇవి తప్పనిసరి.
  • Static Members: ఆబ్జెక్టులతో సంబంధం లేకుండా క్లాస్ మొత్తానికి ఉమ్మడిగా గ్లోబల్ మెమరీలో ఉండే క్లాస్-లెవల్ వేరియబుల్స్ మరియు ఫంక్షన్లు.
  • Empty Class Size: ప్రతి ఆబ్జెక్ట్‌కు ప్రత్యేక మెమరీ అడ్రస్ ఉండటం కోసం ఖాళీ క్లాస్ సైజ్ ఖచ్చితంగా 1 బైట్ ఉంటుంది.

🧠 మీ అవగాహనను పరీక్షించుకోండి (5 Interactive Quizzes):

ప్రశ్న 1: C++ లో class మరియు struct మధ్య ఉన్న ఏకైక సాంకేతిక వ్యత్యాసం ఏమిటి?
సమాధానం: Default Access Specifier మాత్రమే!
వివరణ: struct లో ఏమీ చెప్పకపోతే అన్ని మెంబర్లు డిఫాల్ట్‌గా public అవుతాయి; class లో ఏమీ చెప్పకపోతే అన్ని మెంబర్లు డిఫాల్ట్‌గా private అవుతాయి. మిగిలిన అన్ని ఫీచర్లు (కన్‌స్ట్రక్టర్లు, మెథడ్స్, ఇన్హెరిటెన్స్) రెండింటిలోనూ ఖచ్చితంగా ఒకే విధంగా పనిచేస్తాయి.
ప్రశ్న 2: నాన్-స్టాటిక్ మెంబర్ ఫంక్షన్ లోపల this పాయింటర్ యొక్క డేటా టైప్ ఏమిటి?
సమాధానం: ClassName* const (Constant Pointer to Class Object).
వివరణ: this అనేది ఒక కాన్స్టంట్ పాయింటర్, అంటే this = nullptr; అని దాన్ని మార్చలేము. ఒకవేళ అది const మెంబర్ ఫంక్షన్ అయితే, this యొక్క టైప్ const ClassName* const అవుతుంది.
ప్రశ్న 3: C++ లో ఒక ఖాళీ క్లాస్ (Empty Class) సైజ్ ఎంత ఉంటుంది? అది సున్నా ఎందుకు కాదు?
సమాధానం: 1 బైట్ ఉంటుంది!
వివరణ: C++ స్టాండర్డ్ ప్రకారం ప్రోగ్రామ్‌లోని ప్రతి స్వతంత్ర ఆబ్జెక్ట్‌కు RAM లో ఒక ప్రత్యేకమైన మెమరీ చిరునామా (Unique Address) ఉండాలి. సైజ్ 0 అయితే Empty a, b; &a == &b అయిపోయి రెండు వేర్వేరు ఆబ్జెక్టులు ఒకే చోట ఉన్నట్లు తప్పుడు గందరగోళం ఏర్పడుతుంది.
ప్రశ్న 4: const MyClass obj; అని సృష్టించినప్పుడు, ఆ ఆబ్జెక్ట్ ద్వారా ఏ విధమైన మెంబర్ ఫంక్షన్లను మాత్రమే పిలవగలం?
సమాధానం: కేవలం const మెంబర్ ఫంక్షన్లను మాత్రమే పిలవగలం!
వివరణ: కాన్స్టంట్ ఆబ్జెక్ట్ ఏ మార్పునూ అనుమతించదు. నాన్-కాన్స్ట్ ఫంక్షన్లు వేరియబుల్స్‌ను మార్చే అవకాశం ఉన్నందున కంపైలర్ వాటిని పిలవడానికి అనుమతించదు.
ప్రశ్న 5: స్టాటిక్ మెంబర్ ఫంక్షన్ (Static Member Function) లోపల this పాయింటర్‌ను లేదా నాన్-స్టాటిక్ వేరియబుల్స్‌ను ఎందుకు వాడలేము?
సమాధానం: ఎందుకంటే స్టాటిక్ ఫంక్షన్లు ఏ నిర్దిష్ట ఆబ్జెక్ట్‌తోనూ ముడిపడి ఉండవు (No Instance Context)!
వివరణ: స్టాటిక్ ఫంక్షన్‌ను ఏ ఆబ్జెక్ట్ లేకుండానే నేరుగా ClassName::function() అని పిలవవచ్చు. ఆ సమయంలో ఏ ఆబ్జెక్ట్ సృష్టించబడకపోయినా ఆ ఫంక్షన్ నడుస్తుంది కాబట్టి దానికి this పాయింటర్ గానీ, ఆబ్జెక్ట్-లెవల్ వేరియబుల్స్ గానీ ఉండవు.
← మునుపటి అధ్యాయం: 12. డైనమిక్ మెమరీ తర్వాతి అధ్యాయం: 14. Constructors & Destructors →

ఈ ప్రాజెక్ట్‌ను లైవ్‌గా మన కంపైలర్‌లో రన్ చేయండి!

ఎటువంటి లోకల్ సెటప్ లేకుండా, బ్రౌజర్‌లోనే నేరుగా Modern C++ (GCC 13 / C++20) కంపైలర్‌లో ఈ కోడ్‌ను ఎగ్జిక్యూట్ చేసి రన్‌టైమ్ అవుట్‌పుట్‌ను తనిఖీ చేయండి.