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) ;
} 
Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
user2737926
  • 97
  • 1
  • 1
  • 9

1 Answers1

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.

Community
  • 1
  • 1
Rakib
  • 7,435
  • 7
  • 29
  • 45
  • Thanks. I think I can force the conversion when I am making call. – user2737926 Jun 17 '14 at 06:37
  • like double sum = Data::avg ((Measurable**)fleet ,4) ; Even That seems to help. – user2737926 Jun 17 '14 at 06:37
  • @user2737926, no. Forcing that conversion will yield incorrect behavior. check the link in the reply. – Rakib Jun 17 '14 at 06:38
  • 1
    +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. – Chris Drew Jun 17 '14 at 06:56
  • @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. – Rakib Jun 17 '14 at 07:27