I am trying to implement the modular architecture with C++ where I have a .h
file for every .cpp
file. The files currently only have empty functions:
cycle.h
#include <iostream>
#ifndef CYCLIST_H
#define CYCLIST_H
#pragma once
class cyclist{
private:
double width;
double length;
int helment;
public:
void Predict();
double get_width();
double get_length();
int get_helmet();
};
#endif
cycle.cpp
#include <iostream>
#include "cyclist.h"
void cyclist::Predict(){std::cout << "Predict something!" << std::endl;}
double cyclist::get_width(){}
double cyclist::get_length(){}
int cyclist::get_helmet(){}
vehicle.h
#include <iostream>
#ifndef VEHICLE_H
#define VEHICLE_H
#pragma once
class vehicle{
private:
double width;
double length;
int number_of_doors;
public:
void Predict();
double get_width();
double get_length();
int get_number();
};
#endif
vehicle.cpp
#include <iostream>
#include "vehicle.h"
void vehicle::Predict(){std::cout << "Predict something!" << std::endl;}
double vehicle::get_width(){}
double vehicle::get_length(){}
int vehicle::get_number(){}
As you can see, I am repeating the get_wdith()
, get_height()
, and Predict()
functions. The reason being that each of them will have a different implementation of the same function.
How can I derive all these functions from a base class? If I am using a base class, would/can I still use .h
files?
Edit
So what I created was a single header file Base.h like this:
#include <iostream>
#pragma once
class Base{
public:
virtual ~Base() = default;
virtual void Predict() = 0;
virtual double get_width() = 0;
virtual double get_length() = 0;
virtual int get_number_of_doors() = 0;
virtual bool get_helmet_state();
};
and then I decided to inherit these from cyclist and vehicle classes like this:
cyclist.cpp
#include <iostream>
#include "Base.h"
void Base::Predict(){std::cout << "Predict something!" << std::endl;}
double Base::get_width(){return 0;}
double Base::get_length(){return 0;}
bool Base::get_helmet_state(){return true;}
vehicle.cpp
#include <iostream>
#include "Base.h"
void Base::Predict(){std::cout << "Predict something!" << std::endl;};
double Base::get_width(){return 0;}
double Base::get_length(){return 0;}
int Base::get_number_of_doors(){return 0;}
Now when I run it, I get an error saying that there are multiple definitions of Base::Predict()
. This function will be implemented differently in each class. I tried to add the override
keyword but it didn't let me.
Step One: Apply Liskov Substitution Principle to make sure inheritance makes sense.
Step One-A: Make sure Composition isn't a better fit.
Step Two: Make base class
class Base // For demonstration purposes only. Give this a more descriptive name in your code
{
public:
virtual ~Base() = default;
virtual void Predict() = 0;
virtual double get_width() = 0;
virtual double get_length() = 0;
};
Feel tree to pop this in its own header if you want. Nothing prevents an inheritance hierarchy from using and being divided up into headers.
Depending on your use case, you may or may not need the destructor, but if you're learning C++, make your life easier and put it in. Having it may waste some time at runtime, but you'll have fewer weird problems to have to debug if your inexperience leads you down the wrong path.
All functions you want to override must be declared virtual
. virtual
is sticky, so you don't have to keep repeating it in the derived classes, but keep an eye out for final
.
The = 0
on the end of the virtual
functions makes them pure and makes the class abstract. This may or may not be the behaviour you want, but each of them will have a different implementation strongly hints that it is. Read the linked documentation to be sure.
Step Three: Inherit
class cyclist: public Base{
private:
double width;
double length;
int helment;
public:
void Predict() override;
double get_width() override;
double get_length() override;
int get_helmet();
};
Note that the override
keyword is not a hard requirement, but it can save you a lot of trouble by picking off mistakes, costs only a few seconds to type, an insignificant amount of time to compile, and absolutely nothing at runtime. There are a few win-win situations in the world, so take advantage of this one.
Addendum:
If you have behaviour shared between classes in the overridden functions, consider moving the code for the shared behaviour into a protected
support function and calling the support function from the overridden functions to eliminate the duplication.
class Base // For demonstration purposes only. Give this a more descriptive name in your code
{
protected:
double predict_support();
public:
virtual ~Base() = default;
virtual void Predict() = 0;
virtual double get_width() = 0;
virtual double get_length() = 0;
};
and later in Base.cpp
double Base::predict_support()
{
return do_complicated_math();
}
and then use it something like
void cyclist::Predict()
{
std::cout << "Predict something: " << predict_support() << std::endl;
}