1) None of your functions are virtual, so none can be properly overridden by derived classes.
2) Account joe(100) creates an instance of the class Account, not an instance of the class SavingsAccount. If you want to call calculateInterest on joe, joe needs to be a SavingsAccount. Account, SavingsAccount, and CheckingAccount are all still their own unique classes. SavingsAccount and CheckingAccount inherit Account's data and interface, but Account does not inherit theirs.
3) If you want to instantiate joe as a SavingsAccount but store and treat it like an Account, then you need to make a pointer to Account and upcast it, but you won't have access to a SavingsAccount function if you're treating it like an Account. In that case, you would need to move calculateInterest into Account (and make it pure virtual if desired), then override it in SavingsAccount.
class Account
{
// Add this to your Account class
virtual double calculateInterest() = 0;
};
class SavingsAccount : public Account
{
// Add this to your SavingsAccount class
double calculateInterest() override;
};
Then to create joe as a SavingsAccount but treat it like an Account:
SavingsAccount joe(100);
Account* pJoe = &joe;
double val = joe->calculateInterest(); // calculateInterest is available from Account, but because it's virtual, it calls the one from SavingsAccount.
If you don't want to force all derived classes to implement this function, then you really need to rethink your whole design here. In any case, one cheap way to get around it would be to make it non-pure (remove the = 0 from the declaration, but keep the virtual) and provide a default implementation that returns some default value.
Here is an example of that:
class Account
{
// Add this
virtual double calculateInterest() { return 0.0; }
};
class SavingsAccount : public Account
{
// Add this
double calculateInterest() override; // and use your existing implementation
};
Now if you call calculateInterest on a SavingsAccount, it'll return the SavingsAccount's return value. If you call calculateInterest on a CheckingAccount, it'll return the default implementation provided by Account, which is 0.0. If you call calculateInterest on an Account* pointer to a SavingsAccount instance, it'll return the SavingsAccount's return value, because it is virtual.