user13756099
user13756099

Reputation:

can't call a function for a class member

In the following example, why I can't call car.getFuelConsumption

class Road {
public:
    double length(); // km
    int speed(); // km per hour ;
};

class Car {
protected:
    virtual double getFuelConsumption(int speed_in_km) = 0;
};

class Tank: public Car{
public:
    double getFuelConsumption(int speed_in_km) {
        return 1;
    }
};

double getPetrol(std::vector<Road> roads, const Car &car) {
    double total_fuel_consumption=0;
    for (int i=0;i<roads.size();++i)
    {
        double fuel_consumption_per_road = car.getFuelConsumption(roads[i].speed());
    }
    return total_fuel_consumption;
}

Every car has such a method so why I can't call it? For Example if I send a Tank to getPetrol() then I expect it to work and call Tank's version of getFuelConsumption()


Undefined symbols for architecture x86_64:   "Road::speed()", referenced from:
getPetrol(std::__1::vector<Road, std::__1::allocator<Road> >, Car const&) 
in main.cpp.o ld: symbol(s) not found for architecture
x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

Upvotes: 0

Views: 101

Answers (2)

anastaciu
anastaciu

Reputation: 23832

The visible issues with your code are the following:

  • getPetrol() is defined outside the class and it calls a protected member getFuelConsumption(), protected members can't be called outside the class.

    To fix it you make getFuelConsumption() a public method in the base class.

  • Because you have a const object argument const Car &car, the method getFuelConsumption() needs to have const return, const objects can't call non-const methods. You could also remove const keyword from the car argument, but the first option is adequate in this case.

  • As you are going to use references of the abstract base class to derived classes, effectively polymorphism, the use of a virtual destructor is also advised, under penalty of invoking undefined behavior.

  • The linker error you mention can be because Road methods are declared but not defined, at least not in the code you show.

Corrected code:

Live demo

#include <iostream>
#include <vector>

class Road {
public:
    double length(){ return 0;} // added function body to avoid linker error
    int speed(){ return 0; }    // ""  
};

class Car {
public:
    virtual double getFuelConsumption(int speed_in_km) const = 0;
    virtual ~Car(){} //virtual destructor
};

class Tank : public Car {
public:
    double getFuelConsumption(int speed_in_km) const {
        return speed_in_km;
    }
};

double getPetrol(std::vector<Road> roads, const Car &car) {
    double total_fuel_consumption = 0;
    for (size_t i = 0; i < roads.size(); ++i) {
        total_fuel_consumption += car.getFuelConsumption(roads[i].speed());
    }
    return total_fuel_consumption;
}

Upvotes: 1

Christian Fries
Christian Fries

Reputation: 16952

car is const, but the method is not const. You cannot call a non-const method on a const object. See https://www.learncpp.com/cpp-tutorial/810-const-class-objects-and-member-functions/

Upvotes: 0

Related Questions