3

I have the following two interfaces, which are not part of an inheritance hierarchy. I then have two concrete classes, one which derives from the other.

class ICar {
    public:
    virtual void drive() = 0;
};

class IFastCar {
    public:
    virtual void drive() = 0;
    virtual void driveFast() = 0;
};

class Car : public virtual ICar {
    public:
    void drive() {};
};

class FastCar : public Car, public virtual IFastCar {
    public:
    void driveFast() {};
};

int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();
    return 0;
}

When I compile I get the following error:

error: cannot declare variable `fc' to be of type `FastCar'
error:   because the following virtual functions are abstract:
error:  virtual void IFastCar::drive()

My program will work if I write a function in FastCar to delegate drive() to the base class

void drive() { Car::drive(); }

Is is possible to have FastCar compile without writing methods to delegate to the base class?

Note: ICar and IFastCar are created by two different teams and are in two different projects. The teams have agreed on common method signatures for operations which are shared. I have used inheritance in the implementation classes to attempt to reuse the parts of the implementation which are the same.

brianegge
  • 29,240
  • 13
  • 74
  • 99
  • I think Herb Sutter's [Multiple Inheritance, Part 3](http://www.gotw.ca/gotw/039.htm) might be helpful here, as well as another thread with a somewhat similar problem: http://stackoverflow.com/questions/616380/multiple-inheritance-virtual-function-mess – wkl Oct 12 '11 at 15:57
  • 1
    In your example, FastCar inherits two unrelated interfaces (iCar and iFastCar). Both these interfaces define a *different* pure virtual method drive(). Is that the intent, or should IFastCar inherit from ICar ? – Pascal T. Oct 12 '11 at 16:00

4 Answers4

5

The problem lies in the fact that there's multiple inheritance taking place here ... even though FastCar is derived from Car, the version of drive() in the base-class Car only overrides ICar::drive(), not IFastCar::drive(). Thus, since you are deriving FastCar from IFastCar, you will need to, at some point, define a function in FastCar that also overrides the pure virtual abstract method IFastCar::drive() ... The inherited Car::drive() will not automatically override IFastCare::drive() since it does not inherit from that class. IFastCar::drive() and ICar::drive() are two different pure abstract virtual functions that need to be overridden separately. If you want to make the interface for IFastCar::drive() call your inherited Car::drive() function, then you will need to delegate that inherited function as you've done within a version of FastCar::drive() that specifically calls its base-class' version of drive().

Jason
  • 31,834
  • 7
  • 59
  • 78
3

The problem is that Car does not implement IFastCar::drive but only ICar::drive. The first design question is why does IFastCar not extend the ICar interface and redefines the same operation?

If for some reason that is not an option, then the simplest thing that you can do is actually implement IFastCar::drive() in FastCar by forwarding the request to the Car::drive method:

void FastCar::drive() {
   Car::drive();
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
2

Your use of virtual inheritance here is spurrious, and is a red herring. virtual inheritance is used to derive from common base classes only once; not to bring in only one declaration for matching member signatuires.

So, your FastCar concrete class actually has 3 members, not 2:

virtual void ICar::drive()
virtual void IFastCar::drive()
virtual void IFastCar::driveFast()

The two different drive() appear to be related, so your design appears to be flawed. You don't want virtual inheritance -- you probably want IFastCar to derive from ICar.

class ICar {
    public:
    virtual void drive() = 0;
};

class IFastCar : public ICar {
    public:
    virtual void driveFast() = 0;
};

class Car : public virtual ICar {
    public:
    void drive() {};
};

class FastCar : public IFastCar {
    public:
    void drive() {};
    void driveFast() {};
};

int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();
    return 0;
}

If you then wanted Car to implement some basic functionality that FastCar will employ, then you can derive FastCar from Car, and that is why you would want virtual inheritance. Just remember to apply virtual inheritance at the point just below the top of the diamond:

class ICar {
    public:
    virtual void drive() = 0;
};

class IFastCar : virtual public ICar {
    public:
    virtual void driveFast() = 0;
};

class Car : public virtual ICar {
    public:
    void drive() {};
};

class FastCar : public IFastCar, public Car {
    public:
    void driveFast() {};
};

int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();

    ICar* fc_a = new FastCar;
    fc_a->drive();  // invokes Car::drive() via domination

    return 0;
}

If you compile & run the above code you will get the desired behavior, but at the cost of a compiler warning. On MSVC10 it reads:

1>main.cpp(19): warning C4250: 'FastCar' : inherits 'Car::Car::drive' via dominance
1>          main.cpp(13) : see declaration of 'Car::drive'

This is a warning that your implementation inheritance architecture might be screwed up. And in fact, in most cases it probably is (although in this case not). This can get awful confusing real fast, especially to a maintenance programmer years from now trying to figure out your code. To clear up this confusion and avoid all the compiler warnings, I much prefer (as a rule) delegation to a sister class rather than implementation inheritance.

class ICar {
    public:
    virtual void drive() = 0;
};

class IFastCar : virtual public ICar {
    public:
    virtual void driveFast() = 0;
};

class ICarImpl 
{
public:
    void drive_impl() {};
};

class IFastCarImpl
{
public :
    void driveFast_impl() {};
};

class Car : public virtual ICar, protected ICarImpl {
    public:
    void drive() { drive_impl(); }
};

class FastCar : public IFastCar, protected ICarImpl, protected IFastCarImpl {
    public:
    void driveFast() { driveFast_impl(); }
    void drive() { drive_impl(); }
};

int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();

    ICar* fc_a = new FastCar;
    fc_a->drive();  

    return 0;
}

This accomplishes the usual goal of implementation inheritance -- keeping just one common set of code that can be shared across multiple concrete classes, making maintenance easier.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
0

Since ICar and IFastCar are always cars, you could have IFastCar which derives from ICar,then Car and FastCar implemented like you did.

class ICar {
    public:
    virtual void drive() = 0;
};

class IFastCar : ICar 
{
    public:
    virtual void drive() = 0;
    virtual void driveFast() = 0;
};

class Car : ICar {
    public:
    void drive()
    {
        cout << "driving a normal car" << endl;
    }
};

class FastCar : IFastCar
{
    public:
    void drive()
    {
        cout << "driving a fast car the normal way" << endl;
    }

    void driveFast()
    {
        cout << "driving a fast car at top speed" << endl;
    }
};

int main()
{
    FastCar fc;

    fc.drive();
    fc.driveFast();
    return 0;
}
BlackBear
  • 22,411
  • 10
  • 48
  • 86
  • The question is about avoiding having to implement `FastCar::drive`, which can be tackled in an approach similar to what you provide inheritance in `IFastCar` from `ICar` would have to be virtual, and you will need to remove the `virtual void drive() = 0;` from `IFastCar` (and then you can remove the implementation of `FastCar::drive()`) – David Rodríguez - dribeas Oct 12 '11 at 16:15