University of Wales Trinity Saint David
ACCB5017 - Games Architecture and Mechanics

Inheritance

Overview

This lab builds two related C++ classes, Vehicle and Car, that show how inheritance lets one class reuse and specialise the behaviour of another instead of duplicating it. Starting from a Vehicle class with its own private data and accessors, you will derive a Car class that reuses Vehicle's constructor and replaces its start() message, then construct a Car in main and observe which version of start() actually runs.

Learning Objectives

By the end of this lab you will be able to:

Concept

Suppose a game needs several kinds of vehicle, a Car, a Truck, a Motorbike, each with wheels, doors, an engine, a colour, a make and a model. Writing a full class for each one means copying every private field and every getter and setter into each class, and fixing a bug in one copy does nothing for the others. C++ solves this with inheritance. one class, the base class, defines the shared data and behaviour once, and other classes, derived classes, reuse it automatically and add only what makes them different.

A class derives from another with class Car : public Vehicle. This gives Car every member Vehicle has, without retyping any of them. Vehicle's private fields stay inaccessible to Car directly, so Car still goes through Vehicle's public getters and setters, the same as any other code would. Car's constructor still needs to fill in those private fields, so instead of setting them itself it forwards its arguments to Vehicle's constructor through a member initializer list, Car(...) : Vehicle(...) {}, which runs before Car's own constructor body.

A derived class can also declare a member with the same name as one in its base, such as start(). Unless that member is marked virtual in the base, this does not override it. It hides it. which version runs depends on the declared type used to call it, not on what kind of object it actually is.

Tasks

Task 1 - The Vehicle base class

Open Vehicle.h and complete the Vehicle class. It stores everything a vehicle needs as private state, and exposes it only through public methods.

  1. Declare six private members: wheels and doors as int, and engine, colour, make, model as std::string.
  2. In the constructor, assign each of the six parameters to the matching member using this->.
  3. Implement start() to print The vehicle has started.
  4. Implement the six getters to return their matching member.
  5. Implement the six setters to assign their parameter to the matching member, with two exceptions. setWheels should silently do nothing if given a negative value, and setColour should print a line to the console before assigning if the given colour is "RED".

Success condition: constructing a Vehicle directly and calling start() prints The vehicle has started, and the getters return whatever was last set.

Vehicle.h
#pragma once
#include <string>
#include <iostream>

class Vehicle
{
private:
    // TODO: declare six private members: wheels (int), doors (int),
    // engine, colour, make, model (all std::string)

public:
    Vehicle(int wheels, int doors, std::string engine, std::string colour, std::string make, std::string model)
    {
        // TODO: assign each parameter to the matching private member using this->
    }

    ~Vehicle() {}

    void start()
    {
        // TODO: print "The vehicle has started"
    }

    int getWheels()
    {
        // TODO: return wheels
    }
    int getDoors()
    {
        // TODO: return doors
    }
    std::string getEngine()
    {
        // TODO: return engine
    }
    std::string getColour()
    {
        // TODO: return colour
    }
    std::string getMake()
    {
        // TODO: return make
    }
    std::string getModel()
    {
        // TODO: return model
    }

    void setWheels(int wheels)
    {
        // TODO: ignore negative values, otherwise assign to the wheels member
    }
    void setDoors(int doors)
    {
        // TODO: assign to the doors member
    }
    void setEngine(std::string engine)
    {
        // TODO: assign to the engine member
    }
    void setColour(std::string colour)
    {
        // TODO: if colour is "RED", print a warning line first, then assign
        // it to the colour member either way
    }
    void setMake(std::string make)
    {
        // TODO: assign to the make member
    }
    void setModel(std::string model)
    {
        // TODO: assign to the model member
    }
};

Task 2 - Deriving Car from Vehicle

Open Car.h and complete the Car class so it reuses Vehicle instead of duplicating it.

  1. Change the class declaration so Car derives publicly from Vehicle.
  2. Give Car a constructor with the same six parameters as Vehicle's constructor, and forward all six straight through to Vehicle's constructor using a member initializer list.
  3. Implement Car's own start() to print The car has started.
Car.h
#pragma once
#include "Vehicle.h"
#include <iostream>

class Car // TODO: derive publicly from Vehicle
{
public:
    // TODO: write a constructor taking the same six parameters as Vehicle's
    // constructor, and forward them to Vehicle's constructor using a member
    // initializer list

    ~Car() {}

    void start()
    {
        // TODO: print "The car has started"
    }
};

main.cpp below already constructs a Car and exercises it, so you can test your class as soon as it compiles.

main.cpp
#include <iostream>
#include <string>
#include "Car.h"

int main()
{
    Car* myCar = new Car(4, 2, "1.0L", "blue", "Peugeot", "106");

    myCar->start();
    std::cout << myCar->getMake() << " " << myCar->getModel() << std::endl;

    delete myCar;
}

Success condition: running the program prints The car has started, not The vehicle has started, followed by the make and model from the inherited getters. This works even though Vehicle::start is not marked virtual, because Car::start is a separate function that hides it rather than overriding it.

Solution

Try the tasks above before revealing the solution.