How do you declare an interface in C++?

前端 未结 15 2561
借酒劲吻你
借酒劲吻你 2020-11-22 03:26

How do I setup a class that represents an interface? Is this just an abstract base class?

15条回答
  •  甜味超标
    2020-11-22 04:09

    In C++11 you can easily avoid inheritance altogether:

    struct Interface {
      explicit Interface(SomeType& other)
      : foo([=](){ return other.my_foo(); }), 
        bar([=](){ return other.my_bar(); }), /*...*/ {}
      explicit Interface(SomeOtherType& other)
      : foo([=](){ return other.some_foo(); }), 
        bar([=](){ return other.some_bar(); }), /*...*/ {}
      // you can add more types here...
    
      // or use a generic constructor:
      template
      explicit Interface(T& other)
      : foo([=](){ return other.foo(); }), 
        bar([=](){ return other.bar(); }), /*...*/ {}
    
      const std::function foo;
      const std::function bar;
      // ...
    };
    

    In this case, an Interface has reference semantics, i.e. you have to make sure that the object outlives the interface (it is also possible to make interfaces with value semantics).

    These type of interfaces have their pros and cons:

    • They require more memory than inheritance based polymorphism.
    • They are in general faster than inheritance based polymorphism.
    • In those cases in which you know the final type, they are much faster! (some compilers like gcc and clang perform more optimizations in types that do not have/inherit from types with virtual functions).

    Finally, inheritance is the root of all evil in complex software design. In Sean Parent's Value Semantics and Concepts-based Polymorphism (highly recommended, better versions of this technique are explained there) the following case is studied:

    Say I have an application in which I deal with my shapes polymorphically using the MyShape interface:

    struct MyShape { virtual void my_draw() = 0; };
    struct Circle : MyShape { void my_draw() { /* ... */ } };
    // more shapes: e.g. triangle
    

    In your application, you do the same with different shapes using the YourShape interface:

    struct YourShape { virtual void your_draw() = 0; };
    struct Square : YourShape { void your_draw() { /* ... */ } };
    /// some more shapes here...
    

    Now say you want to use some of the shapes that I've developed in your application. Conceptually, our shapes have the same interface, but to make my shapes work in your application you would need to extend my shapes as follows:

    struct Circle : MyShape, YourShape { 
      void my_draw() { /*stays the same*/ };
      void your_draw() { my_draw(); }
    };
    

    First, modifying my shapes might not be possible at all. Furthermore, multiple inheritance leads the road to spaghetti code (imagine a third project comes in that is using the TheirShape interface... what happens if they also call their draw function my_draw ?).

    Update: There are a couple of new references about non-inheritance based polymorphism:

    • Sean Parent's Inheritance is the base class of evil talk.
    • Sean Parent's Value-semantics and concept-based polymorphism talk.
    • Pyry Jahkola's Inheritance free polymorphism talk and the poly library docs.
    • Zach Laine's Pragmatic Type Erasure: Solving OOP Problems with an Elegant Design Pattern talk.
    • Andrzej's C++ blog - Type Erasure parts i, ii, iii, and iv.
    • Runtime Polymorphic Generic Programming—Mixing Objects and Concepts in ConceptC++
    • Boost.TypeErasure docs
    • Adobe Poly docs
    • Boost.Any, std::any proposal (revision 3), Boost.Spirit::hold_any.

提交回复
热议问题