C++ version of java "implements"

Discussion in 'Mac Programming' started by jmerkow, Jan 20, 2011.

  1. jmerkow, Jan 20, 2011
    Last edited: Jan 20, 2011

    jmerkow macrumors newbie

    Joined:
    Jan 20, 2011
    #1
    I am working on making something that uses multiple inheritance similar to java's implements with interfaces.

    The best I can figure it the only way to do this in C++ is to make a class and make all the functions virtual and use multiple inheritance. Is there a better way to do this?

    Code:
    class Interface
    {
        public:
            virtual void InterfaceFunction() = 0;
    };
    
    class Base
    {
        public:
            virtual int BaseFunction(){\\Does something}
    };
    
    class Derived : public Base, public Interface
    {
        public: 
            void InterfaceFunction(){}
            int BaseFunction(){ return Base::BaseFunction(); } // Is this needed?
    };
    
    
     
  2. jiminaus, Jan 20, 2011
    Last edited: Jan 20, 2011

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #2
    I think a Java interface is just a class of all pure virtual member functions.

    To answer the question in the comment in your code; a class inherits all the protected and public functions from its bases classes. You don't need to re-define a function in a derived class unless you want to change it.

    Oh, and every class with virtual member functions should have a virtual destructor.
     
  3. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #3
    Well, it is not. It is a list of requirements that a class needs to fulfil to be able to claim that it implements the interface. It is the same as an Objective-C protocol. There is just no such thing as an "interface" in C++; C++ doesn't have the runtime support to implement it properly.

    Consider an interface A requiring two methods X and Y, and an interface B requiring two methods X and Z. And you want a class implementing both interfaces. No problem in Java or Objective-C. In C++, the "interface = abstract class" approach just doesn't work.
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    I have asked people who claim to be fluent in C++ what happens if class C in inherits from classes A and B which both have implementations for method Y (with identical parameters and return types) and C does not override this. No one has been able to give me an answer beyond, one will beyond one of the two methods will be called and we don't know which one. I even asked this on a C++ training course and the instructor could not give a reasonable answer. This is one of the reasons I dislike C++ greatly.
     
  5. jiminaus, Jan 21, 2012
    Last edited: Jan 21, 2012

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #5
    I know this an old thread, and I don't know if the OP is interested, but I am because I've just had to turn my mind back to C++.

    As an refresher exercise, I attempt to find a solution to this requirement. Here's what I came up with. I'm rust in C++. This works, but is it good? I'd appreciate a critique.

    One thing that's immediately obvious is the amount of code is going to grow exponentially with the number of interfaces and the number of member functions per interface.

    InterfaceA.h
    Code:
    #ifndef INTERFACEA_H_INCLUDED
    #define INTERFACEA_H_INCLUDED
    
    class InterfaceA
    {
    public:
        virtual void x() = 0;
        virtual void y() = 0;
    };
    
    #endif
    
    InterfaceB.h
    Code:
    #ifndef INTERFACEB_H_INCLUDED
    #define INTERFACEB_H_INCLUDED
    
    class InterfaceB
    {
    public:
        virtual void x() = 0;
        virtual void z() = 0;
    };
    
    #endif
    
    Class.h
    Code:
    #ifndef CLASS_H_INCLUDED
    #define CLASS_H_INCLUDED
    
    #include "InterfaceA.h"
    #include "InterfaceB.h"
    
    class Class
    {
    
    public:
        
        Class();
        
        operator InterfaceA&() { return mInterfaceAProxy; }
        operator InterfaceA*() { return &mInterfaceAProxy; }
        operator InterfaceB&() { return mInterfaceBProxy; }
        operator InterfaceB*() { return &mInterfaceBProxy; }
        
        virtual void x();
        virtual void y();
        virtual void z();
        
        virtual ~Class() = default;
    
    private:
        
        class InterfaceAProxy : public InterfaceA
        {
        public:
            InterfaceAProxy(Class& outer) : mOuter(outer) { }
            void x() override { mOuter.x(); }
            void y() override { mOuter.y(); }
        private:
            Class& mOuter;        
        } mInterfaceAProxy;
        
        class InterfaceBProxy : public InterfaceB
        {
        public:
            InterfaceBProxy(Class& outer) : mOuter(outer) { }
            void x() override { mOuter.x(); }
            void z() override { mOuter.z(); }
        private:
            Class& mOuter;
        } mInterfaceBProxy;
        
    };
    
    #endif
    
    Class.cc
    Code:
    #include "Class.h"
    #include <iostream>
    
    using namespace std;
    
    Class::Class()
    :  mInterfaceAProxy(*this),
       mInterfaceBProxy(*this)
    {
    }
    
    void Class::x() { cout << __PRETTY_FUNCTION__ << endl; }
    void Class::y() { cout << __PRETTY_FUNCTION__ << endl; }
    void Class::z() { cout << __PRETTY_FUNCTION__ << endl; }
    
    Derived.h
    Code:
    #ifndef DERIVED_H_INCLUDED
    #define DERIVED_H_INCLUDED
    
    #include "Class.h"
    
    class Derived : public Class
    {
    public:
        void x() override;
    };
    
    #endif
    
    Derived.cc
    Code:
    #include "Derived.h"
    #include <iostream>
    
    using namespace std;
    
    void Derived::x() { cout << __PRETTY_FUNCTION__ << endl; }
    
    main.cc
    Code:
    #include "Class.h"
    #include "Derived.h"
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void funcTakingA(InterfaceA&);
    void funcTakingB(InterfaceB&);
    
    void
    funcTakingA(InterfaceA& a)
    {
        a.x();
        a.y();
    }
    
    void
    funcTakingB(InterfaceB& b)
    {
        b.x();
        b.z();
    }
    
    int
    main()
    {    
        Class c;
        c.x(); c.y(); c.z();
        cout << "------------------" << endl;
        
        funcTakingA(c);
        funcTakingB(c);
        cout << "------------------" << endl;
        
        Derived d;
        d.x(); d.y(); d.z();
        cout << "------------------" << endl;
        
        funcTakingA(d);
        funcTakingB(d);
        cout << "------------------" << endl;
        
        vector<InterfaceA*> aVec;
        aVec.push_back(c);
        aVec.push_back(d);
        for (InterfaceA* a : aVec)
        {
            funcTakingA(*a);
        }
        cout << "------------------" << endl;
        
        vector<InterfaceB*> bVec;
        bVec.push_back(c);
        bVec.push_back(d);
        for (InterfaceB* b : bVec)
        {
            funcTakingB(*b);
        }
        cout << "------------------" << endl;
        
        return EXIT_SUCCESS;
    }
    
     
  6. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #6
    Since you dug out this old thread anyway: In Objective-C, formal protocols are about the same as Java interfaces. They are most often used for delegate objects. In my own code, I tend not to use formal protocols and delegate objects anymore, but use blocks instead. Much more flexible, much more readable code. And obviously they will work in C++ just as well.
     
  7. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #7
    Alas, Apple's blocks are not yet standard C++. The code I'm writing needs to compile under VS2010 as well.

    I'm sure I've forgotten the pitfalls of C++. I'm currently revising Effective C++ (3e) to try to remember.

    Is there a flaw in this technique I posted? Is there some gotcha that people fresher in C++ can see?
     
  8. Mac_Max macrumors 6502

    Joined:
    Mar 8, 2004
    #8

    I think more than anything, the people you were asking just aren't particularly well read. From Thinking in C++ (Eckel, Bruce) it mentions that in cases like this and in cases with the "Diamond of Death" the first inheritance path will win out (depending on how the vtable is designed on that implementation) in many implementations but that the compiler *should* jump up and down and scream at you for doing it. The proper way to call each version of the class is to cast your derived type pointer to the base class you'd like to call and invoke the function. One way to avoid this problem in the diamond of death is by using virtual inheritance.

    http://progtutorials.tripod.com/cpp2.htm#_Toc50821299

    One example.

    The top answer here shows a way to avoid this in the first place by using an extra inheritance step to name mangle one or both of the conflicting names:

    http://stackoverflow.com/questions/2004820/inherit-interfaces-which-share-a-method-name

    ---

    In terms of pretending to make an interface for C++, I've done it before but have found that the old adage of "composition over inheritance" is often preferable (even in projects in languages that support proper interfaces). When an "interface" is the better way to do it, I follow the guidance demonstrated here:

    http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c
     
  9. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #9
    Thanks for stackoverflow pointers.

    Interesting Item #27 ("Minimize casting") of Effective C++ (3e) explicitly advises against this.

    Say you're override an inherited virtual member function virtFunc() and you want to call the inherited code first.

    The item indicates this is wrong.
    Code:
    void Derived::virtFunc()
    {
      static_cast<Base>(*this).virtFunc();
      // ...
    }
    
    It advises this instead.
    Code:
    void Derived::virtFunc()
    {
      Base::virtFunc();
      // ...
    }
    
     

Share This Page