What's the C++ equivalent of the obj-c delegat

2019-05-29 18:17发布

问题:

Im pretty familiar with obj-c and now I´m trying to dig deeper in C++.

Im looking for a C++ equivalent for obj-c´s delegation pattern.

回答1:

Instead of conforming to a protocol, you just inherit the class (protocol). A small example:

class Delegate 
{
public:
// Some pure virtual method here.
virtual void method() = 0; 
};

class A : Delegate
{
   void method() { // Do something here... };
};

class B
{
   Delegate your_delegate;
   // Somewhere in your code you might need to call the method() using: your_delegate.method();
};


回答2:

There isn't really a 1:1 equivalent. Objective C is a somewhat dynamically typed language. A protocol in Obj-C is like a promise that functions ('selectors') with certain signatures are going to exist at run-time. You don't have to implement them if you don't want to, but you should if you don't want things to crash at runtime, unless they're marked @optional.

C++ by comparison is 100% statically typed. If you say some function should exist, then it has to exist, or the program will not compile. If a superclass declares a function as abstract then subclasses must inherit it. Multiple inheritance (which you need if you want a class to implement multiple decoupled protocols) is a minefield.

The advantage of static typing (C++) is that you can know at compile time whether your program is functionally complete (whether there's code for every place there should be code). However, the cost of this is that sometimes you have to come up with other solutions to fill in for Obj-C's protocols and delegation.



回答3:

The term "delegate" could still well apply. There isn't a syntactic pattern but you model it with a framework using the usual tools.

There's a lot of code here, but the interface is quite clean. What the user must do is just a little code at the bottom. There's still some boilerplate related to constructors, but this will go away in the future with the C++11 "inheriting constructors" syntax.

/* Class to be used as a member of the delegation host.
   Keeps a list of event clients, which you can iterate over.
   As a C++11 convenience, function call operator() is overloaded to call
   all clients with the given argument list.

   This is templated over the base type for the clients. The base type
   should define virtual function(s) for handling the events.
   Templating is necessary because we can't anticipate the number or types
   of these virtual functions. */

template< typename delegate >
struct delegator {
    typedef std::list< delegate * > list; // host interface
    list delegates;

    typedef typename list::iterator delegate_id; // client interface

    delegate_id add( delegate *d )
        { return delegates.insert( delegates.end(), d ); }

    void remove( delegate_id d )
        { delegates.erase( d ); }

#if __cplusplus >= 201103L // C++11-only convenient host interface
    template< typename ... args >
    void operator() ( args && ... a ) {
        for ( auto d : delegates ) ( *d )( std::forward< args >( a ) ... );
    }
#endif
};

/* Abstract base class for all delegate bases. Registers and unregisters
   from the delegator, but doesn't define any event handler. */
template< typename derived >
struct delegate {
    typedef ::delegator< derived > delegator;

    delegator &source;
    typename delegator::delegate_id id;

    delegate( delegator &in_source )
        : source( in_source ),
        id( source.add( static_cast< derived * >( this ) ) ) {}

    virtual ~delegate() { source.remove( id ); }
};

/* Example delegate base. Defines an event handler which clients must implement.
   Other types of events might declare other bases. */
struct my_delegate_base : delegate< my_delegate_base > {
    typedef delegate< my_delegate_base > base;
    typedef base::delegator delegator;
    my_delegate_base( delegator &d ) : base( d ) {}

    virtual void operator() ( int ) = 0;
};

/* Example client class defines how to handle an event. */
struct my_delegate_impl : my_delegate_base {
    my_delegate_impl( delegator &d ) : my_delegate_base( d ) {}

    virtual void operator() ( int i ) {
        std::cout << i << '\n';
    }
};

See it run: https://ideone.com/IRp5rJ