tags:

views:

118

answers:

5

I'm trying to redefine two member functions from their parent's definition.
I don't know if I have it right or not, but something in my code has errors attached and I can't find out what.

some of the header:

class Account 
{
public:
   Account(double);
   void creditBalance(double);
   void debitBalance(double);
   double getBalance() const;
protected:
   double balance;      
};


class CheckingAccount : public Account
{
public:
   CheckingAccount(double, double);
   void feeCreditBalance(double);
   void feeDebitBalance(double);

private:
   double fee = 10;

};

relevant cpp file part:

void Account::creditBalance(double plus)
{
   if(plus > 0)
      balance += plus;
   else
      cout << "Cannot credit negative.";
}

void Account::debitBalance(double minus)
{
   if(minus <= balance)
      balance -= minus;
   else
      cout << "Debit amount exceeded account balance.";
}

void CheckingAccount::feeCreditBalance(double plus)
{
   if(plus > 0){
      balance += plus;
      balance -= fee;
   }
   else
      cout << "Cannot credit negative.";
}

void CheckingAccount::feeDebitBalance(double minus)
{
   if(minus <= balance){
      balance -= minus;
      balance -= fee;
   }
   else
      cout << "Debit amount exceeded account balance.";
}

UPDATE:

I added this:

class Account 
{
public:
   Account(double);
   virtual void creditBalance(double);
   virtual void debitBalance(double);
   double getBalance() const;
protected:
   double balance;      
};

Now I get error: virtual outside class declaration

I could use an example of how to properly initialize fee correctly.

EDIT 2:

I have tried changing the constructor line to this:

CheckingAccount::CheckingAccount(double initBal, double phi) :  Account(initBal), fee(phi)
{
   if(initBal < 0)
      initBal = 0;
   balance = initBal;
   cerr << "Initial balance was invalid.";

   if(phi < 0)
      phi = 0;
   fee = phi;
}

not working, I'm going to work around with changing syntax on the fee(phi) part. I don't know if anyone will respond to this.

A: 

You need to learn overriding the member function ( using virtual keyword) . IF you want to change the base class member function implementation then you need to override those methods and provide different implementation in derived classes.

EDIT:

double fee = 10;

This may be the error which you are talking. Use member initializer list to initialize fee. You cannot initialize fee as in-class constant.

aJ
So would moving the fee into the parent work? I'm going to have to read that page three times to find the part relating to exactly this.
R. Daneel Olivaw
your method of initialization is not correct. initialise fee in derived class constructor.
aJ
+1  A: 

You can not initialise member variables in place(double fee = 10) like that. You have to initialise then in the initiasation list in the derived class constructor. Also note that if you are using inheritance you should make base class destructor virtual.

Naveen
would just adding double fee = 10; into the constructor work? doesn't seem to carry to members.
R. Daneel Olivaw
You should initialize fee as:CheckingBalance::CheckingBalance(double,double): fee(10){}
Naveen
The header hated that. and : fee(10) doesn't make nice with : Account(initBal)
R. Daneel Olivaw
*fee* is a member variable. You declared a new local variable in the CTor. Use *fee = 10;* in the CTor or better use the initialization list: CheckingAccount() : Account(initBal), fee(10) { /* CTor body*/ }
mxp
Did you add comma between Account(initBal) and fee(10)?
Naveen
Good morning, I did that and got "error: 'double CheckingAccount::fee' is a static data member; it can only be initialized at its definition"
R. Daneel Olivaw
A: 

When you want to override a method in the parent class, you should give the method the same name. Don't call it feeCreditBalance if you want it to override creditBalance. Also, you need to use the "virtual" keyword in the definition of the parent class's method if you want a call to creditBalance to always use the one from the child class.

dmazzoni
There are actually two children classes, what should I do if only one wants to use the fee ones.
R. Daneel Olivaw
The problem is that feeCreditBalance isn't a different method. It's the same method, creditBalance, except that when the type of the account is a checking account, it subtracts a fee also. It's not a different *method*, it's a different *implementation* of the same method.A cleaner design would be:void CheckingAccount::creditBalance(double plus){ if(plus > 0) { balance -= fee; } Account::creditBalance(plus);}This reuses as much code as possible.If the other child class doesn't want the fee versions of the methods, it can just keep the method from the parent class.
dmazzoni
I realized that the virtual was correct the second time I read your post, but I have an error for that now too. Also, the credit and debit are supposed to be separated for the assignment. Weird, but I might as well.
R. Daneel Olivaw
If only one subclass needs the functionality provided by the "fee" functions than inheritance is not the correct tool to be using. Inheritance is used to model an "is-a" relationship, it is not just a way to pass functions from one class to another. Look into composition.
Ed Swangren
A: 

If the intention is that for instances of CheckingAccount accounts the versions which use a fee is called, then you want to use virtual methods.

A virtual method is a method decalared (at least in the base class) as "virtual", and has the same name and signiture in any derived classes. When a virtual method is called, it will call the "most derived" version for the instance.

To do this just declare "void creditBalance(double);" and "void debitBalance(double);" virtual (ie "virtual void creditBalance(double);" and "virtual void debitBalance(double);". Then in CheckingAccount rename "feeCreditBalance" and "feeDebitBalance" to "creditBalance" and "debitBalance".

EDIT: Simple example.

Header

class Base
{
public:
    Base(int x);
    //declare virtual so that derived classes may overide it
    virtual void sayHello();
protected:
    int x;
};

class Derived : public Base
{
public:
    Derived(int x, int y);
    //overide Base::sayHello(). the virtual keyword here is optional.
    virtual void sayHello();
protected:
    int y;
};

Cpp

Base::Base(int x)
    :x(x)
{}
Derived::Devired(int x, int y)
    :Base(x), y(y)
{}
void Base::sayHello()
{
    std::cout << "Hello from Base!" << std::endl;
    std::cout << "X = " << x << std::endl;
}
void Derived::sayHello()
{
    std::cout << "Hello from Derived!" << std::endl;
    std::cout << "X = " << x << "  Y = " << y << std::endl;
}

int main()
{
    Base a(5);
    a.sayHello();//"Hello from Base!..."

    Derived b(10, -20);
    b.sayHello();//"Hello from Derived!..."

    Base *c = &b;//take pointer to b, reference would also do
    c->sayHello();//"Hello from Derived!..." because its a Derived instance, eventhough its a Base variable.
}

You can then derive from Derive again (class DerivedAgain : public Derived) and also overload the functions again.

You can also derive multiple subclasses from Base, which can each have their own overrides for the virtual methods, just like I did for the Derived class.

EDIT2: Added variables to example and how to use initialiser list to initialise the base class and member variables.

Fire Lancer
error: virtual outside class declaration x2I can't do anything right.
R. Daneel Olivaw
1 sec, I'll give an example
Fire Lancer
is the syntax wrong in the line "virtual void Account::debitBalance(double minus)"
R. Daneel Olivaw
A: 

I think fee should be static const if it remains constant and does not vary for each object.

//declare in the class like this:

static const double fee;

//define outside class like this:

const double ClassName::fee = 10;

And if u want ur implementation should not allow -Ve balance than something like this and also you should make use of virtual fucntions in inheritance which is better approach:

void CheckingAccount::feeCreditBalance(double plus) {

if(plus - fee > 0)

  balance += (plus - fee);

else

  cout << "Cannot credit negative.";

}

Ashish
It is supposed to default to 10, but still able to change (fee)
R. Daneel Olivaw