1

Base class:

class SavingsAccount
{
public:
    void AddInterest();  // add interest to balance based on APR (interest rate)
private:
    static double APR;
    double Balance;
}

class CheckingAccount: public SavingsAccount
{
private:
    static double APR;
}

I've left out irrelevant members/methods etc. for simplicity.

So, here's the situation: a CheckingAccount should act the same as a SavingsAccount, however it should have a different APR (interest rate). All SavingsAccounts share the same APR and all CheckingAccounts share their own APR (hence the variables being static). This is for an assignment, and we are expected to use static member variables for the APRs.

From my research and tests I can't seem to find any way around overriding the AddInterest() method in the CheckingAccount class to have it use CheckingAccount::APR. If this is the case then most of the methods from SavingsAccount will have to be overridden, as many use the APR, which seems to kill the point of learning to inherit a class.

Am I missing something?

The AddInterest() method, for reference:

SavingsAccount::AddInterest()
{
    double interest = (this->APR/100)/12 * this->getBalance();
    this->setBalance(this->getBalance() + interest);
}

EDIT: The original issue that I ran into (before overriding APR in CheckingAccount) was the following:

int main()
{
    SavingsAccount sav;
    CheckingAccount chk;

    sav.setAPR(0.2);
    chk.setAPR(0.1);

    cout << sav.getAPR() << endl;  // OUTPUTS "0.1"!!

    return 0;
}

Modifying the APR of CheckingAccount objects modifies the APR of SavingsAccount objects! This makes sense to me, since APR is static, but I'm not sure what the best solution is.

Kyle G.
  • 870
  • 2
  • 10
  • 22
  • Are you confusing `private` with `protected`? Also why are you shadowing the definition for `APR`? That creates an independent variable. – tadman Oct 19 '15 at 19:58
  • @tadman hmmm, I haven't tried `protected` yet, but I'll give that a go. Also I'm not sure what you mean be "shadowing the definition." – Kyle G. Oct 19 '15 at 20:01
  • 1
    @KyleG. Shadowing means you can't access `SavingsAccount::APR` from `CheckingAccount` (without explicitly specifying the scope) because `CheckingAccount` also has a member names `APR`. Although `SavingsAccount::APR` is private so you can't access it outside `SavingsAccount` anyway. – Emil Laine Oct 19 '15 at 20:02
  • @zenith ah, that's what I figured. I'd originally designed SavingsAccount with the intention of keeping APR private (it made sense before inheritance came along), but in retrospect that might not have been ideal since CheckingAccount can't use it... – Kyle G. Oct 19 '15 at 20:06
  • @tadman, to add to my earlier response: we were told to avoid using `protected` because of the possible lack of value checking which could load protected variables with "illegal" values. Then again, he just said "avoid" not "NEVER USE THEM" haha – Kyle G. Oct 19 '15 at 20:10
  • Ok, I just tried using `protected: static double APR` and it created the same issue as before. I'll edit my question to explain. – Kyle G. Oct 19 '15 at 20:14
  • You should either remove `static` specifier, or use some `virtual double getAPR()`, or rewrite `CheckingAccount::AddInterest()`. There's no other magic way to do this. – Matt Oct 19 '15 at 20:20
  • @user4419802 that's what I figured (and was afraid of), thanks – Kyle G. Oct 19 '15 at 20:21
  • @KyleG. I'm really not sure what to say about that. `protected` values are pretty common in modern C++ code and there's no risk of using "illegal" values, whatever those are. Maybe the warning was about *uninitialized* values? Don't forget to properly default or populate any and all variables in your constructors. – tadman Oct 19 '15 at 20:23
  • @tadman here's an example of what he meant: `class Time` has member `int hour` that is set using `void setHour(int h)`, which ensures that `hour` is not set to anything outside 1-12. If `int hour` is protected, then a derived class might not make the same checks when setting `hour` (assuming it accesses it directly), which might lead to errors in other functions defined in `Time`. – Kyle G. Oct 19 '15 at 20:28
  • 1
    It all depends on your level of discipline and your coding practices. Generally validators like that are for *external* use, and anyone writing a subclass is expected to restrain themselves and avoid messing around with internals. Merely slapping `private` on everything can make your code a lot more annoying to write, subclasses feel like second class citizens. With great power comes great responsibility! – tadman Oct 19 '15 at 20:35

1 Answers1

3

I would suggest a different class hierarchy:

class Account {};
class SavingsAccount : public Account {};
class CheckingAccount : public Account {};

and then, add a virtual member function to Account:

virtual double getAPR() = 0;

and then, implement Account::AddInterest() using getAPR().

class Account
{
   public:

      virtual ~Account() {}

      // Add other functions as needed
      // ...

      void AddInterest()
      {
         // Implement using getAPR()
         double interest = (this->APR/100)/12 * this->getBalance();
         this->setBalance(this->getBalance() + interest);
      }
      virtual double getAPR() = 0;

   private:
      double Balance;
};

class SavingsAccount : public Account
{
   public:
      virtual double getAPR() { return APR; }
   private:
      static double APR;
}

class CheckingAccount : public Account
{
   public:
      virtual double getAPR() { return APR; }
   private:
      static double APR;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • I appreciate the work, and will probably use this approach in the future, but in this case I'm forced to use the hierarchy described in the question (this is an assignment) – Kyle G. Oct 19 '15 at 20:07
  • @KyleG., are you allowed to add `virtual double getAPR();` to `SavingsAccount`? – R Sahu Oct 19 '15 at 20:08
  • We haven't officially touched on `virtual` yet, so he won't allow it, unfortunately. I'm restricted to syntax and concepts that have been covered. – Kyle G. Oct 19 '15 at 20:11
  • @KyleG., That's unfortunate. I feel bad for you. I lost respect for your instructor. Good luck with the class. – R Sahu Oct 19 '15 at 20:13
  • `virtual` is something that should be covered in day one of C++ classes. Plus, it's absurd that something's limited because it's "too advanced". What is the point of learning if you're being held back? The whole function of getting an education is to push yourself ahead. – tadman Oct 19 '15 at 20:24
  • @tadman I agree wholeheartedly. I feel like I'm coding with casts on both hands, lol. Although to be fair, most of the students are still struggling to grasp the concept of a pointer... – Kyle G. Oct 19 '15 at 20:32
  • @RSahu, I'll talk to my prof about the hierarchy today. Maybe he'll approve some modifications (and/or the use of virtual). – Kyle G. Oct 19 '15 at 20:32
  • One question about your code: why the `= 0` in `virtual double getAPR() = 0;`? – Kyle G. Oct 19 '15 at 20:33
  • @KyleG., That syntax is used to define pure virtual member functions. All concrete derived classes must have an implementation of the function. Otherwise, you can't construct them. – R Sahu Oct 19 '15 at 20:36
  • 1
    Some students just don't have the right mind-set to even begin to learn how to program, and others are already there, waiting for more. The way they throw everyone into the same program is not unlike trying to teach English literature when half the class can't even read. – tadman Oct 19 '15 at 20:37