How can I simulate interfaces in C++?

后端 未结 9 2100
时光说笑
时光说笑 2020-12-04 19:22

Since C++ lacks the interface feature of Java and C#, what is the preferred way to simulate interfaces in C++ classes? My guess would be multiple inheritance o

相关标签:
9条回答
  • 2020-12-04 20:03

    Interfaces in C++ are classes which have only pure virtual functions. E.g. :

    class ISerializable
    {
    public:
        virtual ~ISerializable() = 0;
        virtual void  serialize( stream& target ) = 0;
    };
    

    This is not a simulated interface, it is an interface like the ones in Java, but does not carry the drawbacks.

    E.g. you can add methods and members without negative consequences :

    class ISerializable
    {
    public:
        virtual ~ISerializable() = 0;
        virtual void  serialize( stream& target ) = 0;
    protected:
        void  serialize_atomic( int i, stream& t );
        bool  serialized;
    };
    

    To the naming conventions ... there are no real naming conventions defined in the C++ language. So choose the one in your environment.

    The overhead is 1 static table and in derived classes which did not yet have virtual functions, a pointer to the static table.

    0 讨论(0)
  • 2020-12-04 20:08

    There is no good way to implement an interface the way you're asking. The problem with an approach such as as completely abstract ISerializable base class lies in the way that C++ implements multiple inheritance. Consider the following:

    class Base
    {
    };
    class ISerializable
    {
      public:
        virtual string toSerial() = 0;
        virtual void fromSerial(const string& s) = 0;
    };
    
    class Subclass : public Base, public ISerializable
    {
    };
    
    void someFunc(fstream& out, const ISerializable& o)
    {
        out << o.toSerial();
    }
    

    Clearly the intent is for the function toSerial() to serialize all of the members of Subclass including those that it inherits from Base class. The problem is that there is no path from ISerializable to Base. You can see this graphically if you execute the following:

    void fn(Base& b)
    {
        cout << (void*)&b << endl;
    }
    void fn(ISerializable& i)
    {
        cout << (void*)&i << endl;
    }
    
    void someFunc(Subclass& s)
    {
        fn(s);
        fn(s);
    }
    

    The value output by the first call is not the same as the value output by the second call. Even though a reference to s is passed in both cases, the compiler adjusts the address passed to match the proper base class type.

    0 讨论(0)
  • 2020-12-04 20:11

    If you don't use virtual inheritance, the overhead should be no worse than regular inheritance with at least one virtual function. Each abstract class inheritted from will add a pointer to each object.

    However, if you do something like the Empty Base Class Optimization, you can minimize that:

    struct A
    {
        void func1() = 0;
    };
    
    struct B: A
    {
        void func2() = 0;
    };
    
    struct C: B
    {
        int i;
    };
    

    The size of C will be two words.

    0 讨论(0)
  • 2020-12-04 20:13

    Interfaces in C++ can also occur statically, by documenting the requirements on template type parameters.

    Templates pattern match syntax, so you don't have to specify up front that a particular type implements a particular interface, so long as it has the right members. This is in contrast to Java's <? extends Interface> or C#'s where T : IInterface style constraints, which require the substituted type to know about (I)Interface.

    A great example of this is the Iterator family, which are implemented by, among other things, pointers.

    0 讨论(0)
  • In C++ we can go further than the plain behaviour-less interfaces of Java & co. We can add explicit contracts (as in Design by Contract) with the NVI pattern.

    struct Contract1 : noncopyable
    {
        virtual ~Contract1();
        Res f(Param p) {
            assert(f_precondition(p) && "C1::f precondition failed");
            const Res r = do_f(p);
            assert(f_postcondition(p,r) && "C1::f postcondition failed");
            return r;
        }
    private:
        virtual Res do_f(Param p) = 0;
    };
    
    struct Concrete : virtual Contract1, virtual Contract2
    {
        ...
    };
    
    0 讨论(0)
  • 2020-12-04 20:18

    By the way MSVC 2008 has __interface keyword.

    A Visual C++ interface can be defined as follows: 
    
     - Can inherit from zero or more base
       interfaces.
     - Cannot inherit from a base class.
     - Can only contain public, pure virtual
       methods.
     - Cannot contain constructors,
       destructors, or operators.
     - Cannot contain static methods.
     - Cannot contain data members;
       properties are allowed.
    

    This feature is Microsoft Specific. Caution: __interface has no virtual destructor that is required if you delete objects by its interface pointers.

    0 讨论(0)
提交回复
热议问题