动态指针转换

3

我想将一个基类指针转换为派生类指针,作为函数参数传递,但是不使用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强制转换为一个派生指针来避免这种情况。

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

我希望创建一个回调函数映射表,该表将自动类型转换基类指针,并根据派生类的类型调用相应的函数。

我将拥有许多派生类类型,并且将有一个相应的函数,该函数将是一个派生类类型。 - slash_axl
你可以为foo构建一个调度机制,根据派生类的类型将其分派到相应的实现上,但这并不简单。 - R Sahu
2
@RSahu:或者它可以是:http://coliru.stacked-crooked.com/a/2497baf83177a9e0 - Mooing Duck
@RSahu:好的,请这样做。可以优化为迭代每个派生类型的调度程序,然后调用该特定派生类型的函数,这可能会略微更快,但代码量更大。对于这种用例来说可能不值得。 (请注意,我的代码处理重载函数的能力不是很好,但可以修复) - Mooing Duck
这种实现方式很诱人,但仍需遍历所有可用的回调函数。不过我的派生类都有类型变量,因此我可以使用映射而不是向量来避免迭代。 - slash_axl
显示剩余2条评论
1个回答

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);
}

输出:

进入fooImpl(Derived1 :: Ptr)。
进入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);
}

感谢您的实现。 - slash_axl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接