C ++ - access to multiple object interfaces with a single pointer

I need to save a container of pointers to objects. These objects have some common methods / attributes (interface) that I want to use (possibly at compile time) and use. Example:

struct A{
    void fly(){}
};

struct B{
    void fly(){}
};

A a;
B b;
std::vector<some *> objects;
objects.push_back(&a);
objects.push_back(&b);

for(auto & el: objects)
    el->fly();

A simpler solution would be A, and Binherit a common base class, for example FlyingClass:

struct FlyingClass{
    void fly(){}
};
struct A: public FlyingClass { ...
struct B: public FlyingClass { ...

and create

std::vector<FlyingClass *> objects;

This will work, as well as ensure the fact that I can only add objectsthings that can fly (implement FlyingClass).

But what if I need to implement some other common methods / attributes WITHOUT binding them to the above base class?

Example:

struct A{
    void fly(){}
    void swim(){}
};

struct B{
    void fly(){}
    void swim(){}
};

And I would like to:

for(auto & el: objects) {
    el->fly();
    ...
    el->swim();
    ...
}

, , , /, :

void dostuff(Element * el){
    el->fly();
    el->swim();
}

, :

struct SwimmingClass{
    void swim(){}
};

struct A: public FlyingClass, public SwimmingClass { ...
struct B: public FlyingClass, public SwimmingClass { ...

?

std::vector<FlyingClass&&SwimmingClass *> objects;

, SwimmingFlyingClass, , RunningClass .. . , , ?

- ? , .

+4
3

TMP-, . , . - , , , ++ .

, :

struct AnyBase { virtual ~AnyBase() {} }; // All derived classes inherit from.
template<typename... T> class Limited {
    AnyBase* object;
    template<typename U> Limited(U* p) {
        static_assert(all<is_base_of<T, U>...>::value, "Must derive from all of the interfaces.");
        object = p;
    }        
    template<typename U> U* get() {
        static_assert(any<is_same<U, T>...>::value, "U must be one of the interfaces.");
        return dynamic_cast<U*>(object);
    }
}

, . static_assert , U T. , U T , all .

, U T.... , dynamic_cast , .

, .

std::vector<Limited<Flying, Swimming>> objects;
for(auto&& obj : objects) {
    obj.get<Flying>()->fly();
    obj.get<Swimming>()->swim();
}
+1

-, , .

.

, ? dynamic_cast .

class Entity { }

class SwimmingEntity : public Entity {
  virtual void swim() = 0;
}

class FlyingEntity : public Entity {
  virtual void fly() = 0;
}

class Fish : public SwimmingEntity {
  void swim() override { }
}

class Bird : public FlyingEntity {
  void fly() override { }
}

std:vector<Entity*> entities;

, Entity. , dynamic_cast rtti ( rtti), ?

0

, .

, ( ) , (), , -, :

#include <iostream>
#include <vector>
#include <memory>

using std::cout;

struct Bird {
  void fly() { cout << "Bird flies\n"; }
  void swim(){ cout << "Bird swims\n"; }
};

struct Pig {
  void fly() { cout << "Pig flies!\n"; }
  void swim() { cout << "Pig swims\n"; }
};

struct FlyingSwimmingThing {
  // Pure virtual interface that knows how to fly() and how to swim(),
  // but does not depend on type of underlying object.
  struct InternalInterface {
    virtual void fly() = 0;
    virtual void swim() = 0;

    virtual ~InternalInterface() { }
  };

  // Proxy inherits from interface; forwards to underlying object.
  // Template class allows proxy type to depend on object type.
  template<typename T>
  struct InternalImplementation : public InternalInterface {
    InternalImplementation(T &obj) : obj_(obj) { }
    void fly() { obj_.fly(); }
    void swim() { obj_.swim(); }
    virtual ~InternalImplementation() { }
  private:
    T &obj_;
  };

  // Templated constructor
  template<typename T>
  FlyingSwimmingThing(T &obj) : proxy_(new InternalImplementation<T>(obj))
  { }
  // Forward calls to underlying object via virtual interface.                  
  void fly() { proxy_->fly(); }
  void swim() { proxy_->swim(); }

private:
  std::unique_ptr<InternalInterface> proxy_;
};

int main(int argc, char *argv[])
{
  Bird a;
  Pig b;

  std::vector<FlyingSwimmingThing> objects;
  objects.push_back(FlyingSwimmingThing(a));
  objects.push_back(FlyingSwimmingThing(b));

  objects[0].fly();
  objects[1].fly();
  objects[0].swim();
  objects[1].swim();
}

deleter shared_ptr std:: function, , , - .

"" -. , , - , , clone() ( new). , , , ...

[]

, , , , ...

, fly() swim(), , ; - .

, -, fly() swim(), . ( , , , dostuff.) ""; fly() swim(), , .

Finally, it should be possible to create a new otherwise unrelated class with its own fly()and swim()functions and have a wrapper holding a pointer to that class (a) without changing the wrapper class, and (b) without touching the call fly()or swim()through the wrapper.

This, as I said, is a feature of type erase textbook. I did not invent an idiom, but I recognize her when her name is.

0
source

All Articles