views:

3239

answers:

5

In C++, is it possible to have a base plus derived class implement a single interface?

For example:

class Interface
{
    public:
        virtual void BaseFunction() = 0;
        virtual void DerivedFunction() = 0;
};

class Base
{
    public:
        virtual void BaseFunction(){}
};

class Derived : public Base, public Interface
{
    public: 
        void DerivedFunction(){}
        // EDIT: I didnt mean to put this here
        // void BaseFunction(){ Base::BaseFunction(); }
};

void main()
{
    Derived derived;
}

This fails because Derived can not be instantiated. As far as the compiler is concerned Interface::BaseFunction is never defined.

So far the only solution I've found would be to declare a pass through function in Derived

class Derived : public Base, public Interface
{
    public: 
        void DerivedFunction(){}
        void BaseFunction(){ Base::BaseFunction(); }
};

Is there any better solution?


EDIT: If it matters, here is a real world problem I had using MFC dialogs.

I have a dialog class (MyDialog lets say) that derives from CDialog. Due to dependency issues, I need to create an abstract interface (MyDialogInterface). The class that uses MyDialogInterface needs to use the methods specific to MyDialog, but also needs to call CDialog::SetParent. I just solved it by creating MyDialog::SetParent and having it pass through to CDialog::SetParent, but was wondering if there was a better way.

+12  A: 

C++ doesn't notice the function inherited from Base already implements BaseFunction: The function has to be implemented explicitly in a class derived from Interface. Change it this way:

class Interface
{
    public:
        virtual void BaseFunction() = 0;
        virtual void DerivedFunction() = 0;
};

class Base : public Interface
{
    public:
        virtual void BaseFunction(){}
};

class Derived : public Base
{
    public: 
        virtual void DerivedFunction(){}
};

int main()
{
    Derived derived;
}

If you want to be able to get away with only implementing one of them, split Interface up into two interfaces:

class DerivedInterface
{
    public:
        virtual void DerivedFunction() = 0;
};

class BaseInterface
{
    public:
        virtual void BaseFunction() = 0;
};

class Base : public BaseInterface
{
    public:
        virtual void BaseFunction(){}
};

class Derived : public DerivedInterface
{
    public: 
        virtual void DerivedFunction(){}
};  

class Both : public DerivedInterface, public Base {
    public: 
        virtual void DerivedFunction(){}
};

int main()
{
    Derived derived;
    Base base;
    Both both;
}

Note: main must return int
Note: it's good practise to keep virtual in front of member functions in the derived that were virtual in the base, even if it's not strictly required.

Johannes Schaub - litb
If you do it that way, then you don't need the second declaration of BaseFunction.
Torlack
It's what he wrote. I didnt want to change it. He might have reason to di it like that
Johannes Schaub - litb
i've made a comment on that. thanks :)
Johannes Schaub - litb
No problem, I just didn't want him or others to go through eternity thinking it was needed. :)
Torlack
2 problems: - Now BAse cannt be instantiated on it's own.- Other classes that derive from base now have to implement DerivedFunction class OtherDerived : public Base { public: void OtherDerivedFunction(){} };
Joe
I edited the code. I didn't mean to put the second declaration of BaseFunction
Joe
Make two interfaces, one for BaseFunction and one for DerivedFunction.
Greg Rogers
In your original example, you couldn't instantiate Base anyway. The second problem is also an issue with your original example.
Torlack
Yes, Joe. You need to do two interfaces then. It doesn't work this way like in Java.
Johannes Schaub - litb
i added the two-interfaces solution
Johannes Schaub - litb
I like your answers, but I think the pass-through function is actually easiest. Your Both class defines its own implementation, while I'd want a way to use the implementations in Base and Derived. I realize that I very well could be designing my classes like a fool. :)
Joe
For the second bit, I think you meant "class Derived : public Base, public DerivedInterface"
Joe
I didn't mean it. but if you wanted that behaivor, i can indeed change it
Johannes Schaub - litb
+1  A: 

The problem is that with your example, you have two implementations of Interface, the one coming from Base and the one coming from Derived. This is by design in the C++ language. As already pointed out, just remove the Interface base class on the definition of Derived.

Torlack
um.. no.... Check the code again. Base does not inherit from Interface. (Interface has DerviceFunction which is not implemented in Base)
James Curran
+4  A: 

It looks like it's not quite the case that Derived "is-a" Base, which suggests that containment may be a better implementation than inheritance.

Also, your Derived member functions should be decalred as virtual as well.

class Contained
{
    public:
        void containedFunction() {}
};

class Derived
{
    public:
        virtual void derivedFunction() {}
        virtual void containedFunction() {return contained.containedFunction();}
    private:
        Containted contained;
};

You can make the contained member a reference or smart pointer if you want to hide the implementation details.

JohnMcG
+1  A: 

I agree with the answer by litb. However, there's an opportunity here to understand something of how virtual functions and multiple inheritance work.

When a class has multiple base classes, it has separate vtables for each base class. Derived will have a vtable structure that looks like this:

Derived
 vtable: Interface
   BaseFunction*
   DerivedFunction*
 vtable: Base
   BaseFunction*

Additionally, each base class will only be able to see its own vtable. When Base is instantiated, it fills in the Base::BaseFunction pointer in the vtable, but can't see the vtable for Interface.

If the code you provided could compile, the resulting vtable structure of an instance of Derived would look like this:

Derived
 vtable: Interface
   BaseFunction* = 0
   DerivedFunction* = Derived::DerivedFunction
 vtable: Base
   BaseFunction* = Base::BaseFunction
Kennet Belenky
A: 

I found one thing lacking from litb's answer. If I have a Derived instance, I can get a DerivedInterface and BaseInterface. But if I only have a DerivedInterface I can't get a BaseInterface since deriving DerivedInterface from BaseInterface won't work.

But, this whole time I've been limiting myself to compile time checking for some reason. This DerivedInterface works just great:

class DerivedInterface
{
    public:
        virtual void DerivedFunction() = 0;
        BaseInterface* GetBaseInterface()
            {return dynamic_cast<BaseInterface*>(this);}
};

void main()
{
    Derived derived;

    DerivedInterface* derivedInterface = &derived;
    derivedInterface->GetBaseInterface()->BaseFunction();
}

No pass through functions necessary in Derived, and everyone is happy. Sure, it's not strictly an interface anymore, but that's fine. Why didn't I think of that sooner? :)

Joe
that's no problem. you just make a class derive from DerivedInterface and BaseInterface, and then you have exactly the interface of your "Interface" class in your original question
Johannes Schaub - litb
anyway. never use dynamic_cast like that :) dynamic_cast should be a last resort to work around what one cannot do by designing correct interfaces. in your case, just do Interface as i told in the comment above, and then you can do BaseInterface* baseInterface = and call both :)
Johannes Schaub - litb
Yes, that will give me the same interface, but a different implementation, which is the whole point. I have the implementation for a base and derived class, and I need a single interface for them. It sounds like this is as close as I'll get.
Joe
wait, I was referring to you "both" class about which defines its own implementation. Hmmmm.
Joe