C++: How to force class users to override at the same time get the benefit of delegation to the base class ?

C++: How to force class users to override at the same time get the benefit of delegation to the base class ?

Here is the practical use case where Abstract class instantiation is not allowed at the same time making use of Abstract class default implementation.

Walkthrough the example C++ slowly and carefully,

/******************** Account.hpp ********************/
#include <iostream>

class Account{

private:
    static constexpr const char *def_name = "Unnamed Account";
    static constexpr double def_balance = 0.0;

protected:
    std::string name;
    double balance;

public:
    Account(std::string name = def_name, double balance = def_balance);
    virtual bool deposit(double amount) = 0 ;
    virtual bool withdraw(double amount) = 0 ;
    double get_balance() const ;
    
    virtual ~Account() = default;

};
/******************** Account.cpp ********************/
Account::Account(std::string name, double balance)
    :name(name), balance(balance) {
}

bool Account::deposit(double amount) {

    std::cout << "Inside Account deposit()" << std::endl;

    if(amount < 0) {
        return false;
    } 
    else {
        balance = balance + amount;
        return true;
    }
    
}

bool Account::withdraw(double amount) {

    if (balance >= amount) {
        balance = balance - amount;
        return true;
    } else {
        return false;
    }
}

double Account::get_balance() const {
    return balance;
}
/******************** Savings_Account .hpp ********************/
class Savings_Account : public Account {

private:
    static constexpr const char *def_name = "Unnamed Savings Account";
    static constexpr double def_balance = 0.0;
    static constexpr double def_int_rate = 0.0;

protected:
    double int_rate;

public:
    Savings_Account(std::string name = def_name, double balance = def_balance, double int_rate = def_int_rate);
    virtual bool deposit(double amount) override;
    virtual bool withdraw(double amount) override ;
    virtual ~Savings_Account() = default;
    
};
/******************** Savings_Account .cpp ********************/
Savings_Account::Savings_Account(std::string name, double balance, double int_rate)
    :Account(name, balance), int_rate(int_rate) {
}

bool Savings_Account::deposit(double amount) {
    std::cout << "Inside Savings_Account deposit()" << std::endl;
    amount = amount + (amount * (int_rate / 100));
    return Account::deposit(amount);
}
bool Savings_Account::withdraw(double amount) {
    return Account::withdraw(amount);
}
/******************** main.cpp ********************/
int main(){
    
    //Account acc("Vijay", 1000); // This is Abstract class, instanting is forbidden
    
    Account *s_acc_ptr = new Savings_Account("Tamil", 4000, 5);
    s_acc_ptr->deposit(1000);
    s_acc_ptr->withdraw(500);  // Correctly called due to virtual
    
    std::cout << "balance is "<< s_acc_ptr->get_balance() <<std::endl;
    return 0;
}        

here, Account class is Abstract class due to holding of 2 pure virtual functions. So creating the object of this Abstract class is not allowed by compiler.

    virtual bool deposit(double amount) = 0 ;
    virtual bool withdraw(double amount) = 0 ;         

At the same time, these methods are provide with default definition in the same Abstract class which can be called by derived class as a delegation.

In Saving_Account constructor "name" and "balance" initialization by delegating to its Abstract base class.

Similarly Saving_Account::withdraw() is delegated to Abstract base class's Account::withdraw () as there is no need of separate logic in derived class.

Savings_Account::Savings_Account(std::string name, double balance, double int_rate)
    :Account(name, balance), int_rate(int_rate) {
}

// AND

bool Savings_Account::withdraw(double amount) {
    return Account::withdraw(amount);
}        

Last one, Savings_Account::deposit() add its own business logic and reuse Account::deposit() offered by the Abstract class

bool Savings_Account::deposit(double amount) {
    std::cout << "Inside Savings_Account deposit()" << std::endl;
    amount = amount + (amount * (int_rate / 100));
    return Account::deposit(amount);  // Delegation to Base class
}        

Conclusion:

So, We are reusing the base class implementation at the same time ensuring Abstract class is not instantiateable.


To view or add a comment, sign in

More articles by M Vijaynath

Insights from the community

Others also viewed

Explore topics