0

I am new to C++. I am learning Inheritance in C++. I am unable to understand the compile time error. I have Super class Measurable and Car and Country derive from Measurable. In Measurable I have pure virtual function getMeasurable which is overridden by subclass. I have Data class which iterate through Measurable objects (Cars or Country) and compute average.

I am hitting the error

measure.cc: In function ‘int main()’:
measure.cc:70: error: invalid conversion from ‘Car**’ to ‘Measurable**’
measure.cc:70: error:   initializing argument 1 of ‘static int Data::avg(Measurable**, int)’

Code

#include <iostream>
 class Measurable ;

 class Measurable {
    public:
        virtual int getMeasurable() = 0 ;
};

 class Country: public Measurable {
    private: 
        int size ;
    public:
        Country(int size): size(size) {
        }
        int getMeasurable() {
            return size ;
        }
};

 class Car: public Measurable {
    private: 
        int mileage ;
    public:
        Car(int size): mileage(size) {
    }
        int getMeasurable() {
            return mileage ;
        }
};

class Data {

    public:
        static int avg ( Measurable* obj[] , int num) {
            double size = 0 ; 
            for (int i = 0 ; i < num ;i++) 
            {

                size += obj[i]->getMeasurable() ; 
            }
            return size/num ;
        }
};

int main () {


    Car* fleet[] = {
                    new Car (1) , new Car (2) , new Car (3) , new Car (4) 
    };

    double sum = Data::avg (fleet ,4) ;
} 
5
  • c++ tip #1 avoid heap memory, use stl types. Instead of Car * fleet[] use std::vector<Car>` Commented Jun 17, 2014 at 5:58
  • don't use polymorphic array. Commented Jun 17, 2014 at 6:01
  • @ChrisDrew I dont see any reason why this couldnt all be stack memory? static int avg ( Measurable* obj[] , int num) could be static int avg ( const std::vector<Measurable> &obj, int num) and there would be no performance loss or difference in the output. Commented Jun 17, 2014 at 6:15
  • @Ben, you can't store a Car in a std::vector<Measurable> Commented Jun 17, 2014 at 6:20
  • @ChrisDrew isnt that why static_cast and dynamic_cast and templates exist. Also you could use a std::vector<Measurement *> and it would be at least a little better. Commented Jun 17, 2014 at 6:26

1 Answer 1

3

The error message is clear, Car** and Measurable** are different types, and not implicitly convertible (although Car* can be converted to Measurable*). Also it is dangerous to use polymorphic array. Here is one solution you can try:

template<class T>
class Data {

  public:
    static double avg ( vector<T>& obj) {
        double size = 0 ; 
        for (int i = 0 ; i < obj.size() ;i++) 
        {

             size += obj[i].getMeasurable() ; 
        }
        return size/obj.size() ;
      }
};

int main () {

      vector<Car> fleet;
      fleet.push_back( Car(1));
      fleet.push_back( Car(2));
      fleet.push_back( Car(3));
      fleet.push_back( Car(4));

      double sum = Data<Car>::avg (fleet) ;

      cout<<sum<<endl;
  } 

If you want to create other classes inheriting from Measurable, and want to use the method in generic way then you can use pointer, but you have to manually allocate/deallocate them.

class Data {

 public:
static double avg ( vector<Measurable*> obj) {
    double size = 0 ; 
    for (int i = 0 ; i < obj.size() ;i++) 
    {

        size += obj[i]->getMeasurable() ; 
    }
    return size/obj.size() ;
}
};



int main () {


vector<Measurable*> fleet;
fleet.push_back(new Car(1));
fleet.push_back(new Car(2));
fleet.push_back(new Car(3));
fleet.push_back(new Car(4));

double sum = Data::avg (fleet) ;

cout<<sum<<endl;

for (int i=0;i<fleet.size();i++)
{
    delete fleet[i];
}

fleet.clear();
} 

Note that, the base class destructor should be always virtual.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks. I think I can force the conversion when I am making call.
like double sum = Data::avg ((Measurable**)fleet ,4) ; Even That seems to help.
@user2737926, no. Forcing that conversion will yield incorrect behavior. check the link in the reply.
+1 for the function template but if you are also going to suggest using base class pointers you need to point out that base class needs a virtual destructor. Also, I would prefer smart pointers.
@ChrisDrew, good points. using virtual destructor is kind of mandatory, but I skipped smart pointer as I think atleast one should be familiar in handling pointers at learning phase.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.