1

Vehicle class is an abstract base class for ElectricVehicle and GasolineVehicle classes, and HybridVehicle class inherits from ElectricVehicle and GasolineVehicle.

I have two 'Vehicle':base class undefined errors in ElectricVehicle.h and GasolineVehicle.h. I know I am messing up the #include files somehow, but I'm having trouble figuring that out.

I tried removing the Vehicle.cpp in ElectricVehicle.cpp and GasolineVehicle.cpp and adding the Vehicle header file, but that came up with a bunch of other errors.

Vehicle.h

#pragma once
#ifndef Vehicle_h
#define Vehicle_h

class Vehicle {
    
public:
    // check here  // 4 lines
    float engineEfficiency;
    virtual float calculateRange() = 0;
    virtual float percentEnergyRemaining() = 0;
    virtual void drive(float) = 0;
    virtual ~Vehicle();
};
#endif

Vehicle.cpp

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

using namespace std;

Vehicle::~Vehicle() {
    cout << "In vehicle destructor" << endl;
}

ElectricVehicle.h

#pragma once
#include <iostream>

#ifndef ElectricVehicle_h
#define ElectricVehicle_h

class ElectricVehicle : virtual public Vehicle {
public:
    float maximumCharge;
    float currentCharge;
    float engineEfficiency;

public:
    ElectricVehicle(float max, float eff);
    float calculateRange();
    float percentEnergyRemaining();
    void drive(float km);
    ~ElectricVehicle();
};
#endif

ElecticVehicle.cpp

#pragma once
#include "Vehicle.cpp"
#include "ElectricVehicle.h"
using namespace std; 

ElectricVehicle::ElectricVehicle(float maxEnergy, float rating) {
    engineEfficiency = rating;
    maximumCharge = maxEnergy; 
    currentCharge = maxEnergy;
}

ElectricVehicle::~ElectricVehicle() {
    cout << "In Electric vehicle destructor" << endl;
}

float ElectricVehicle::calculateRange() {
    return (currentCharge * 100 / engineEfficiency);
}

float ElectricVehicle::percentEnergyRemaining() {
    return (currentCharge * 100.0f / maximumCharge);
}

void ElectricVehicle::drive(float km) {
    if (currentCharge < 0) {
        cout << "Your Car is out of energy";
        return;
    }
    currentCharge -= (km / 100) * engineEfficiency;
}

GasolineVehicle.cpp

#include "Vehicle.cpp"
#include "GasolineVehicle.h"

using namespace std; 

GasolineVehicle::GasolineVehicle(float maxEnergy, float rating) {       
    engineEfficiency = rating;
    maximumGasoline = maxEnergy;
    currentGasoline = maxEnergy;
}

GasolineVehicle::~GasolineVehicle() {
    cout << "In Gasoline vehicle destructor" << endl;
}

float GasolineVehicle::calculateRange() {
    return currentGasoline * 100 / engineEfficiency;
}

float GasolineVehicle::percentEnergyRemaining() {
    return (currentGasoline * 100.0f / maximumGasoline);
}

void GasolineVehicle::drive(float km) {
    if (currentGasoline < 0){
        cout << "Your Car is out of energy";
        return;
    }
    currentGasoline -= (km / 100) * engineEfficiency;
}

Gasoline.h

#pragma once
#include <iostream>

#ifndef GasolineVehicle_h
#define GasolineVehicle_h

class GasolineVehicle : virtual public Vehicle {
public:
    float maximumGasoline;
    float currentGasoline;
    float engineEfficiency;
    GasolineVehicle(float max, float eff);
    ~GasolineVehicle();
    float calculateRange();
    float percentEnergyRemaining();
    void drive(float km);
};
#endif

HybridVehicle.cpp

#pragma once
#include "ElectricVehicle.h"
#include "GasolineVehicle.h"
#include "HybridVehicle.h"

#include<iostream>

using namespace std;

// hybridvehicle constructor is calling its parent class constructors;
HybridVehicle::HybridVehicle(float maxGasoline, float gasefficiency, float maxcharge, float electricefficiency) :GasolineVehicle(maxGasoline, gasefficiency), ElectricVehicle(maxcharge, electricefficiency) {}
    
HybridVehicle::~HybridVehicle() {
    cout << "In Hybrid vehicle destructor" << endl;
}

// :: is scope resolution operator as both gasoline and electric vehicle classes having engine efficiency the compiler
// will be confused of which variable to take.. so we :: to remove ambuiguity
float HybridVehicle::calculateRange() {
    return (currentCharge / ElectricVehicle::engineEfficiency) * 100 + (currentGasoline / GasolineVehicle::engineEfficiency) * 100;
}

float HybridVehicle::percentEnergyRemaining() {
    return ((currentCharge + currentGasoline) / (maximumCharge + maximumGasoline)) * 100.0f;
}

void HybridVehicle::drive(float km) {
    if (currentGasoline + currentCharge < 0) {
        cout << "Your Car is out of energy";
        return;
    }
    else if (currentCharge > 0) {
        currentCharge -= (km / 100) * ElectricVehicle::engineEfficiency;
    }
    else
    {
        currentGasoline -= (km / 100) * GasolineVehicle::engineEfficiency;
    }
}

HybridVehicle.h

#pragma once

#ifndef HybridVehicle_h
#define HybridVehicle_h

class HybridVehicle: public GasolineVehicle, public ElectricVehicle {
public:
    HybridVehicle(float gMax, float gEff, float eMax, float eEff);
    ~HybridVehicle();
    float calculateRange();
    float percentEnergyRemaining();
    void drive(float km);
};
#endif

Week2.cpp

#pragma once
#include "Vehicle.cpp"
#include "HybridVehicle.cpp"

using namespace std;

Vehicle* testVehicle(Vehicle* pVehicle, const char* vehicleName) {
    cout << vehicleName << " s range is: " << pVehicle->calculateRange() << endl;
    pVehicle->drive(150);
    cout << vehicleName << " s energy left is: " << pVehicle->percentEnergyRemaining() << endl;
    cout << vehicleName << " s range is now: " << pVehicle->calculateRange() << endl;

    return pVehicle;
}

int main(int argc, char** argv)
{
    //50L of gas, 7.1 L/100km
    delete testVehicle(new GasolineVehicle(50, 7.1), "Corolla");

    //42 L of gas, 4.3 L/100km, 8.8kWh, 22 kWh/100km
    delete testVehicle((GasolineVehicle*)new HybridVehicle(42, 4.3, 8.8, 22.0), "Prius");

    //75 kWh, 16 kWh/100km
    delete testVehicle(new ElectricVehicle(75, 16), "Tesla 3");

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Including `.cpp` files in other files is wrong. Instead you should include the `.h` file corresponding to the base class in the `.h` file of the derived class. I didn't go through all of the code to see if that is the only issue. Please provide a [mre]. – user17732522 Jul 08 '22 at 18:51
  • 1
    You're missing `#include "Vehicle.h"` in all other header files. How can compiler know what class are you inheriting from? And as above commenter said, do not `#include` .cpp files, ever. – Yksisarvinen Jul 08 '22 at 18:52
  • 2
    The code in `main` should _really_ not look like this. What is the reason for using `new` and `delete`? They definitively don't belong there. And a C-style cast like this is also dangerous (and unnecessary). – user17732522 Jul 08 '22 at 18:54
  • as for that I am not sure, it was a requirement. @user17732522 – Alice Smith Jul 08 '22 at 18:59
  • I don't know what you mean by "_a requirement_", but that is bad style. Better would be e.g.: `HybridVehicle hybrid(42, 4.3, 8.8, 22.0); testVehicle(static_cast(&hybrid), "Prius");`. The `static_cast` isn't really needed though, since `Vehicle` is a `virtual` base, so it will also convert without it. And `testVehicle` should really probably take the argument by-reference, not by-pointer. – user17732522 Jul 08 '22 at 19:06
  • You only need one header guard per file. If you're using `#pragma once`, don't also include the `#ifndef _somename_h` stuff. – 3Dave Jul 08 '22 at 19:10
  • Actually, NEVER `#ifndef _somename_h`. The preceding underscore in `_somename_h` violates [the language naming rules](https://stackoverflow.com/q/228783/4581301). – user4581301 Jul 08 '22 at 19:13
  • Side note: There are tactical reasons to use both `#pragma once` and `#ifndef` header guards, but it doesn't come up all that often. Where supported, `#pragma once` can speed things up because the header doesn't need to be read at all, but where it's not supported ([or not trustworthy](https://stackoverflow.com/a/34884735/4581301)) `#ifndef` can still save your bacon. – user4581301 Jul 08 '22 at 19:17
  • @user4581301: Modern compilers recognize the header-guard pattern, so it’s not any slower. If you’re willing to pay two whole lines (horror!) to use the standards-conforming mechanism, you should just do that. – Davis Herring Jul 08 '22 at 20:24
  • That shouldn't surprise me, but it kind of does. – user4581301 Jul 08 '22 at 20:29

0 Answers0