0

[The code below is runnable so feel free to run it to see what I am talking about]

I am following along with a tutorial from a book that is Java-based. The code below is essentially a bunch of classes that can be used to accurately get the description and price of a beverage ordered (no matter how many additional condiments are added on to the base Beverage). The issue is the getDescription() and cost() functions in the Beverage class are not being overridden by the CondimentDecorator class, or any of the various condiment classes (Mocha, Milk, Whip, etc.).

When I run it, "Unknown Beverage" prints out as the description.

How can I figure out where the inheritance bug is at?

#include <iostream>
#include <string>
using namespace std;

class Beverage {
    string description = "Unknown Description";
    public:
    string getDescription(){
       return description;
    }
    int cost(); // just declare it - don't do anything
};

class HouseBlend : public Beverage {
    string description = "House Blend";

    string getDescription(){
       return description;
    }

    int count(){
        return .89;
    }
};

class DarkRoast : public Beverage {
    string description = "Dark Roast";

    string getDescription(){
        return description;
    }

    int count(){
       return .99;
    }
};

class Decaf : public Beverage {
    string description = "Decaf";

    string getDescription(){
       return description;
    }

    int count(){
       return 1.05;
    }
};

class Espresso : public Beverage {
    string description = "Espresso";

    string getDescription(){
       return description;
    }

    int count(){
       return 1.99;
    }
};

class CondimentDecorator : public Beverage {
    string getDescription();
};

class Soy : public CondimentDecorator {
    Beverage *beverage;
    public:
    Soy(Beverage *beverage){
       this->beverage = beverage;
    }

    string getDescription(){
       return beverage->getDescription() + " , Soy ";
    }

    int cost(){
        return beverage->cost() + .15;
    }
};

class Milk : public CondimentDecorator{
    Beverage *beverage;
    public:
    Milk(Beverage *beverage){
       this->beverage = beverage;
    }

    string getDescription(){
       return beverage->getDescription() + " , Milk ";
    }

    int cost(){
       return beverage->cost() + .10;
    }
};

class Mocha : public CondimentDecorator{
    Beverage *beverage;
    public:
    Mocha(Beverage *beverage){
       this->beverage = beverage;
    }

    string getDescription(){
       return beverage->getDescription() + " , Mocha ";
    }

    int cost(){
       return beverage->cost() + .20;
    }
};

class Whip : public CondimentDecorator{
    Beverage *beverage;
    public:
    Whip(Beverage *beverage){
       this->beverage = beverage;
    }

    string getDescription(){
       return beverage->getDescription() + " , Whip ";
    }

    int count(){
       return beverage->cost() + .10;
    }
};

    //class StarbuzzCoffeeRun {
    int main(){
            Beverage *beverage = new Espresso;
            cout << beverage->getDescription(); // << "$" << beverage->cost() << endl ;
            Beverage *beverage2 = new DarkRoast;
            beverage2 = new Mocha(beverage2);
            cout << beverage2->getDescription();
            beverage2 = new Mocha(beverage2);
            beverage2 = new Whip(beverage2);
           cout << beverage2->getDescription(); // << "$" << beverage2->cost() << endl ;

            Beverage *beverage3 = new HouseBlend;
            beverage3 = new Soy(beverage3);
            beverage3 = new Mocha(beverage3);
            beverage3 = new Whip(beverage3);
            cout << beverage3->getDescription(); // << "$" << beverage3->cost() << endl ;
          return 0;
        }
halfer
  • 19,824
  • 17
  • 99
  • 186
  • 4
    `Can someone please help me figure out where the Inheritance bug is at?` The main problem is `I am following along with a tutorial from a book that is Java-based.` Get a good C++ book and work through _that_ if you want to write C++. – tkausl Jan 25 '20 at 00:30
  • Make `getDescription` virtual in your base class. Then it should work. – Paul Sanders Jan 25 '20 at 00:31
  • Thanks Paul! Could you explain how I'm misunderstanding Inheritance overrides? I thought for sure having the same function name in the other classes would override the Beverage class's functionality. – Lollipop Bunny Jan 25 '20 at 00:33
  • 2
    I would recommend you [read a good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – Paul Sanders Jan 25 '20 at 00:34
  • Virtual inheritance has performance implications. Unlike many, and probably most, object oriented languages C++ only turns it on if you ask for it to be turned on. In general C++ follows a policy of "You only pay for what you use", so don't assume C++ will do anything friendly like bounds checking or input validation unless you write it or ask for it. – user4581301 Jan 25 '20 at 00:42

1 Answers1

3

Couple of things wrong here.

The biggest one (causing the problem you're seeing) is that by doing something like this:

class HouseBlend : public Beverage {
    string description = "House Blend";

    // ...
};

What you're actually doing here is declaring a new member description, not setting Beverage's description.

To actually set Beverage's variable description, you will need to set it in a constructor or something:

class HouseBlend : public Beverage { 
    public:
    HouseBlend () {
        description = "House Blend";
    }
};

Of course, if you want to access a parent's variable inside the child, it will have to be public or protected:

class Beverage {
    protected:
    string description = "Unknown Description";
    public:
    string getDescription(){
       return description;
    }
    int cost(); // just declare it - don't do anything
};

Of course, you could set it in a setter too, but you you get the idea.


The other thing wrong here is with your count() function:

int cost(); // just declare it - don't do anything

There are 2 things wrong with this:

  1. It needs to be virtual. If it's not, it will just end calling the base function and not the overloaded one when you create a pointer to it.
virtual int cost(); // so the compiler knows it will get overloaded at runtime
  1. It needs to have an implementation. Even if the function does nothing, it still needs to have an "implementation" or else the compiler will complain.
virtual int cost() {return 0;} // Return some value that we know shouldn't exist

If you have a virtual function, you have the option of a pure virtual function which allows you to have no implementation, but override it in the child class:

virtual int cost() = 0; // This function has no implementation, but derived classes will give it one.

Note that this makes Beverage into a abstract class, and that comes with some restrictions for how you can use it. However, you seem to use it like an abstract class, so I'm guessing that this is what you were expecting anyway.


Edit

So, after I hit "post," I realized that technically I didn't answer your question which seems to be why getDescription() doesn't get overridden. The answer is similar to cost(), in that it needs to be virtual as well:

class Beverage {
    string description = "Unknown Description";
    public:
    virtual string getDescription(){
       return description;
    }

    virtual int cost() = 0;
};

This will technically allow getDescription() to get overridden when you use it in a pointer context. However, this isn't the best solution. It is probably better in the long run to make description protected instead.

Otherwise you're making a bunch of extra description variables you don't need. That will ultimately waste memory. And it makes your design clunkier. So just use protected instead.