0

I am trying to write this program using base classes and derived classes where there is a truck with a maximum capacity of 8 tons. Then this truck is loaded with 1.5 tons of apple and then loaded with 0.5 tons of kiwi. This would then diminish the amount of tons remaining to 6.5 when the apples are loaded and then to 6 when the kiwis are loaded. This is an assignment and in the main function I see they are calling the function loadCargo as follows truck.loadCargo(Apple()), I am unsure of what this is accomplishing. Please take a look at the complete code:

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

class Cargo{
public:
    double c = 0;
    double getAmount(){
        return c;
}
};


class Apple : public Cargo{
public:
    double c = 1.5;
    double getAmount(){
        return c;
}
};

class Kiwi : public Cargo{
public:
    double c = 0.5;
    double getAmount(){
        return c;
        }
}; 

class Truck {
    double maxCapacity = 8;
public:
    void loadCargo(Cargo cargo){
    maxCapacity = maxCapacity - cargo.getAmount();
}
        void printInfo(){
            cout << maxCapacity << " tons remaining" << endl;
        }
};


int main() {
    Truck truck;
    truck.printInfo();

        truck.loadCargo(Apple());
        truck.printInfo();

        truck.loadCargo(Kiwi());
        truck.printInfo();
}

I thought that truck.loadCargo(Apple()) would pass an object of Apple to the object cargo. Therefore when loadCargo is called, it would access the getAmount function in Apple class and not in class Cargo but that is not happening. The output should be:

8 tons remaining
6.5 tons remaining
6 tons remaining

But currently it is the following since it just using the getAmount from the Cargo class:

8 tons remaining
8 tons remaining
8 tons remaining

EDIT: Since this is an assignment I cannot change anything in the main function or in the line that has void loadCargo(Cargo cargo).

Rivf
  • 123
  • 8

2 Answers2

2

First, you need to make your getAmount() function virtual:

class Cargo{
public:
    double c = 0;
    virtual double getAmount(){
        return c;
    }
};

Then, your derived classes will override the getAmount() function with their version.

Without the virtual keyword, if your function accepts a parameter of type Cargo, it will just used the Cargo::getAmount() function.

Second, you need to pass your object into by const-reference, like this:

class Truck {
    double maxCapacity = 8;
public:
    void loadCargo(const Cargo& cargo){
        maxCapacity = maxCapacity - cargo.getAmount();
    }
    ...

This will ensure that your cargo object inside the loadCargo function will refer to an Apple object or a Kiwi object. By passing by value, you're copying your Apples object into a Cargo object, and you fall over the slicing problem.

ETA: You would also need to change your getAmount() function to const like this:

//                 vvvvv
double getAmount() const {
    return c;
}

Since you mention you cannot change your Truck class, you can do this by setting the value of c in your Cargo class constructor. Like this:

class Cargo{
public:
    double c;

    // Constructor, using an initializer list to set the value of `c`.
    Cargo(const double c_value) :
        c(c_value) {
    }

    double getAmount(){
        return c;
    }
};

Then, in your Apple and Kiwi classes, set the value of c inside the constructor, like this:

class Apple : public Cargo{
public:
    // Set the Cargo's mass in the Apple constructor...
    Apple() :
        Cargo(1.5) {
    }

    // getAmount() function removed.
};

Finally, remove the getAmount() functions from your Apple and Kiwi classes (but KEEP for the Cargo class).

Final Note

Please bear in mind that passing Cargo by value will always suffer from the Slicing Problem (see link above) and should be avoided, though because your Apple and Kiwi objects don't have any member variables, it will still work for your assignment. If inheritance is how your instructor wanted this to work, then passing Cargo by value into loadCargo(Cargo cargo) is bad C++ practice. This doesn't impact your assignment, but if you wish to take C++ seriously, bear this in mind for the future!

Karl Nicoll
  • 16,090
  • 3
  • 51
  • 65
  • I am getting ```error: cannot bind non-const lvalue reference of type 'Cargo&' to an rvalue of type 'Cargo'|```. Also, I would like to avoid changing the implementation of ``void loadCargo(Cargo cargo)`` since this is an assignment and I am not supposed to alter that line. – Rivf Nov 05 '20 at 23:57
  • 1
    @Rivf I have added an extra part to my answer that avoids changing the `loadCargo()` function :-) – Karl Nicoll Nov 06 '20 at 00:41
1

When you make this call:

truck.loadCargo(Apple());

You are indeed passing an Apple to truck. However, the declaration of loadCargo takes a Cargo object:

void loadCargo(Cargo cargo)

This slices the Apple and now you simply have a Cargo object that you call getAmount on. This returns 0, and so the maxCapacity doesn't change.

There are various ways to fix this, but the simplest would be to make loadCargo a template, so that it can accept any type without first converting it to a Cargo object:

template<typename Fruit>
void loadCargo(Fruit cargo)

Here's a demo.


Note that for this implementation, so long as Apple and Kiwi have the same member functions as expected of a Cargo object, you can avoid inheriting from a base class entirely.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • Oh ok, I understand. Is it possible to do this without altering the ``void loadCargo(Cargo cargo)``? As I mentioned this is an assignment and it is prohibited to change that line. – Rivf Nov 05 '20 at 23:55
  • @Rivf Oh, you can't change `Truck` either? Are you sure? Accepting a `Cargo` by value is not going to work, I think. See the other answer, maybe that's what you're looking for. You'll still have to change the definition of `loadCargo` though. – cigien Nov 05 '20 at 23:58
  • I can change the contents of ``class Truck``, I just can't mess with that one line that contains ``void loadCargo(Cargo cargo)``. – Rivf Nov 06 '20 at 00:01
  • Can you edit your question to show *exactly* which parts of the code are fixed, and which parts you wrote? – cigien Nov 06 '20 at 00:25