动态指针投射

时间:2014-05-27 18:18:09

标签: c++ inheritance smart-pointers

我想将基类指针转换为派生类指针作为函数参数,而不使用dynamic_pointer_cast

class Base 
{
    public:     
    typedef std::shared_ptr < Base > Ptr;
    virtual ~Base ( );
    ...
};

class Derive : public Base
{
    public:
    typedef std::shared_ptr < Derive > Ptr;
    ...
};

void foo( Derive::Ptr ptr )
{
    ... 
}

Base::Ptr ptr1 ( new Derive );
foo( ptr1 );

上面的代码在调用foo时会出错。通过使用std :: dynamic_pointer_cast将ptr1类型转换为Dervie指针可以避免这种情况。

Base::Ptr ptr1 ( new Derive );
foo ( std::dynamic_pointer_cast < Derive > ( ptr1 ) );

我想创建一个回调函数映射,它将自动对基类指针进行类型转换,并根据派生类的类型调用相应的函数。

1 个答案:

答案 0 :(得分:2)

这适合我。

#include <iostream>
#include <set>
#include <memory>

class Base 
{
    public:     
    typedef std::shared_ptr < Base > Ptr;
    virtual ~Base () {}
};

// Dispatch mechanism to dispatch derived class specific
// functions for foo.

// Base class.
struct FooDispatcher
{
   static int registerDispatcher(FooDispatcher* dispatcher)
   {
      dispatcherSet.insert(dispatcher);;
      return 0;
   }

   static void dispatch(Base::Ptr ptr)
   {
      std::set<FooDispatcher*>::iterator iter = dispatcherSet.begin();
      std::set<FooDispatcher*>::iterator end = dispatcherSet.end();
      for ( ; iter != end; ++ iter )
      {
         if ( (*iter)->canProcess(ptr) )
         {
            (*iter)->process(ptr);
            return;
         }
      }
   }

   virtual bool canProcess(Base::Ptr ptr) = 0;
   virtual void process(Base::Ptr ptr) = 0;

   static std::set<FooDispatcher*> dispatcherSet;
};

std::set<FooDispatcher*> FooDispatcher::dispatcherSet;

void foo( Base::Ptr ptr )
{
   FooDispatcher::dispatch(ptr);
}

// A class template for derived classes to use when they
// have an implementation of foo.
template <typename T>
struct FooDerivedDispatcher : public FooDispatcher
{
   virtual bool canProcess(Base::Ptr ptr)
   {
      return (std::dynamic_pointer_cast<T>(ptr) != nullptr);
   }

   virtual void process(Base::Ptr ptr)
   {
      fooImpl(std::dynamic_pointer_cast<T>(ptr));
   }
};

// Derived1 and its implementation of foo.
class Derived1 : public Base
{
    public:
    typedef std::shared_ptr < Derived1 > Ptr;
};

void fooImpl( Derived1::Ptr ptr )
{
   std::cout << "Came to fooImpl(Derived1::Ptr).\n";
}

// Register the FooDispatcher for Derived1
int dummy1 = FooDispatcher::registerDispatcher(new FooDerivedDispatcher<Derived1>());

// Derived2 and its implementation of foo.
class Derived2 : public Base
{
    public:
    typedef std::shared_ptr < Derived2 > Ptr;
};

void fooImpl( Derived2::Ptr ptr )
{
   std::cout << "Came to fooImpl(Derived2::Ptr).\n";
}

// Register the FooDispatcher for Derived1
int dummy2 = FooDispatcher::registerDispatcher(new FooDerivedDispatcher<Derived2>());

// Test...    
int main()
{
   Base::Ptr ptr(new Derived1);
   foo(ptr);

   ptr = Base::Ptr(new Derived2);
   foo(ptr);
}

输出:

Came to fooImpl(Derived1::Ptr).
Came to fooImpl(Derived2::Ptr).

<强>更新

更简单的调度机制......感谢@MooingDuck。

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

class Base 
{
    public:     
    typedef std::shared_ptr < Base > Ptr;
    virtual ~Base () {}
};

struct FooDispatcher {
    template<class Derived, class Func>
    bool registerFunction(Func func) {
        auto lambda = [=](std::shared_ptr<Base>& ptr)->void {
            std::shared_ptr<Derived> d = std::dynamic_pointer_cast<Derived>(ptr);
            if (d)
                func(std::move(d));
        };
        functions.push_back(lambda);
        return true;
    }
    void dispatch(std::shared_ptr<Base>& ptr)
    {
        for(auto& func : functions)
            func(ptr);
    }
private:
    std::vector<std::function<void(std::shared_ptr<Base>&)>> functions;
};

FooDispatcher dispatcher;

void foo( Base::Ptr ptr )
{
   dispatcher.dispatch(ptr);
}

class Derived1 : public Base
{
    public:
    typedef std::shared_ptr < Derived1 > Ptr;
};

void fooImpl1( Derived1::Ptr ptr )
{
   std::cout << "Came to fooImpl(Derived1::Ptr).\n";
}

class Derived2 : public Base
{
    public:
    typedef std::shared_ptr < Derived2 > Ptr;
};

void fooImpl2( Derived2::Ptr ptr )
{
   std::cout << "Came to fooImpl(Derived2::Ptr).\n";
}

int main()
{
   dispatcher.registerFunction<Derived1>(fooImpl1);
   dispatcher.registerFunction<Derived2>(fooImpl2);

   Base::Ptr ptr(new Derived1);
   foo(ptr);

   ptr = Base::Ptr(new Derived2);
   foo(ptr);
}