Start learning free

LESSON 558 OF 568 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Shipping Options in C++: Inheritance and Virtual Methods

Practice O(1) Read the full explanation

An online shop offers three ways to ship a parcel. Standard shipping is the basic one. Express and Economy are kinds of shipping too: they answer the same two questions, what the option is called and what it costs, but each in its own way. So each one overrides the parent's methods with its own versions.

Implement the class Shipping, the standard option:

  • name() returns "Standard".
  • cost(weight) returns 5 + weight: a base price of 5, plus 1 for each kilogram.

and two classes that inherit from Shipping and override both methods:

  • Express: name() returns "Express", and cost(weight) returns 10 + 2 * weight.
  • Economy: name() returns "Economy", and cost(weight) returns 3 plus half the weight, rounded down to a whole number: half of 7 is 3.

The input lists parcels, one per line: the option (standard, express or economy) and the weight. For each line, the code that tests your classes creates that option and prints <name>: <cost> from its name() and cost(weight). The two calls are the same for every option (where variables have types, through a variable of the parent type Shipping); because the methods are overridden, each option answers with its own version. The starter code spells these names the way your language does.

 

Example 1:

Input:
    standard 4
    express 4
    economy 4
Output:
    Standard: 9
    Express: 18
    Economy: 5
Explanation: The same parcel of 4 kilograms costs 5 + 4 = 9 with Standard, 10 + 2 × 4 = 18 with Express
and 3 + 2 = 5 with Economy (half of 4 is 2).

Example 2:

Input:
    standard 0
    express 0
    economy 0
Output:
    Standard: 5
    Express: 10
    Economy: 3
Explanation: With a weight of 0, only the base prices are left.

Example 3:

Input:
    economy 7
    economy 1
    standard 7
    express 7
Output:
    Economy: 6
    Economy: 3
    Standard: 12
    Express: 24
Explanation: Economy halves the weight and rounds down: half of 7 is 3, so 3 + 3 = 6, and half of 1 is 0, so 3 + 0 = 3.

 

Constraints:

  • 0 <= weight <= 1000, a whole number of kilograms.
  • At most 100 parcels per test case.
STEP 1 OF 6
    Ctrl + Enter to check

    C++ · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Shipping Options in C++, explained

    Problem overview

    You write three classes. Shipping is the standard option and the parent. Express and Economy inherit from it, and each one replaces both of its methods with its own versions. Every option answers the same two questions: name() returns its name, and cost(weight) returns the price of a parcel of that many kilograms.

    Classname()cost(weight)
    Shipping"Standard"5 + weight
    Express"Express"10 + 2 * weight
    Economy"Economy"3 + weight / 2

    For a parcel of 4 kilograms the three options give 9, 18 and 5. The lesson's tests call the same two methods on every option and print name: cost, so each class has to give its own answer when called through a pointer to Shipping.

    A second example, with a weight of 7: Standard costs 5 + 7 = 12, Express costs 10 + 2 * 7 = 24, and Economy costs 3 + 7 / 2. In whole-number division 7 / 2 is 3, so Economy costs 6. Economy is the only option where the fraction matters, and the statement asks for it to be rounded down.

    Approach: one parent, three versions of each method

    The parent defines what every shipping option can do. A child class inherits that and may override a method: write a method with the same name and parameters that replaces the parent's version for objects of the child class.

    Two keywords make this work in C++:

    • virtual in the parent says that a call may need to run a child's version. The call is decided by the real class of the object at run time, not by the type of the pointer.
    • override in the child asks the compiler to check that the method really overrides a virtual method of the parent.

    The starter code already has both keywords in place. Your job is to write the bodies.

    Think of what happens at the call s->cost(4) when s has type Shipping*. The compiler only knows that s points to some Shipping. Because cost is virtual, the program looks at the object itself when the call runs. If the object is an Economy, Economy::cost runs and returns 3 + 4 / 2, which is 5. If it is a plain Shipping, the parent's version runs and returns 9. This is called polymorphism: one call, many behaviours, chosen by the object.

    Step by step

    1. Write Shipping::name: return "Standard".
    2. Write Shipping::cost: a base price of 5 plus 1 per kilogram, so 5 + weight.
    3. Write Express::name: return "Express".
    4. Write Express::cost: 10 + 2 * weight. Without this method an express parcel would get the parent's price.
    5. Write Economy::name: return "Economy".
    6. Write Economy::cost: 3 + weight / 2.

    Each class overrides only for itself. Changing Express has no effect on Economy or on Shipping.

    The solution in C++

    class Shipping {
    public:
        virtual string name() {
            return "Standard";
        }
    
        virtual int cost(int weight) {
            return 5 + weight;
        }
    };
    
    class Express : public Shipping {
    public:
        string name() override {
            return "Express";
        }
    
        int cost(int weight) override {
            return 10 + 2 * weight;
        }
    };
    
    class Economy : public Shipping {
    public:
        string name() override {
            return "Economy";
        }
    
        int cost(int weight) override {
            return 3 + weight / 2;
        }
    };
    

    Using the classes

    Because all three classes share the type Shipping, one pointer type can hold any of them, and the same two calls work on each:

    Shipping standard;
    Express express;
    Economy economy;
    Shipping* options[] = {&standard, &express, &economy};
    for (Shipping* s : options) {
        cout << s->name() << ": " << s->cost(7) << "\n";
    }
    

    This prints:

    Standard: 12
    Express: 24
    Economy: 6
    

    The loop never asks which class it holds. A fourth option, say Overnight, would work in the same loop without changing it.

    Details that matter

    • public: comes first in each class because members of a class are private by default.
    • : public Shipping makes Express and Economy children of Shipping whose public methods stay public.
    • Pointers call methods with ->, and objects with a dot. In the loop above s is a pointer, so it is s->cost(7).
    • If you create options with new and delete them through a Shipping*, the parent should also have a virtual destructor, written virtual ~Shipping() = default;. The lesson's tests don't need it, and the starter code leaves it out here.
    • weight / 2 divides two ints, so the fraction is dropped: with a weight of 7 it gives 3, and the cost is 6. Writing (3 + weight) / 2 instead would give 5 for the same weight, because the 3 would be halved too.

    Edge cases and common mistakes

    • Forgetting virtual in the parent. The code still compiles, but a call through a Shipping* then runs the parent's method. With non-virtual name and cost in Shipping, an Express object used through a Shipping* prints Standard: 9 for a weight of 4, while the same object used directly prints Express: 18.
    • A header that doesn't match. If the child's method differs from the parent's, even by a const after the parameter list, override turns the mistake into a compiler error: marked 'override', but does not override. Without override the mismatch would silently create a second, unrelated method.
    • Weight 0. Only the base prices are left: 5, 10 and 3.
    • Odd weights in Economy. Weights 1 and 7 give 3 and 6, because the half is rounded down.

    Testing

    Try these weights with all three options, in the order Standard, Express, Economy:

    WeightStandardExpressEconomy
    49185
    05103
    712246
    16123

    Try it in the editor above.

    Keep going with C++500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free