指向成员函数的函数

时间:2014-04-25 17:46:09

标签: c++ scope function-pointers

我有点复杂的情况。它可以很容易地通过继承来解决,但我现在很好奇,并且由于其他一些原因我会以这种方式解决它。

我有一个表示算法的类,并且随着时间的推移已经实现了不同的解决方案。目前,我有原班级,它的成员是新成员。 我会同时使用算法和开关来根据情况使用它们。

#include "B.h"
class A {
public:
    typedef void ( A::*FooFunction )( float, float );
    A::FooFunction m_fooFunction;
    B m_b;

    A( WhichUseEnum algorithm ) : m_b( B() )
    {
        switch( algorithm ) {
        case ALG_A:
            m_fooFunction = &A::FooFunctionOfA;
            break;
        case ALG_B:
            m_fooFunction = ??? // something like: m_b.FooFunctionOfA
            break;
        }
    }

    void FooFunction( float a , float b)
    {
         ( this->*m_fooFunction )( a, b );
    }

    void FooFunctionOfA( float, float ); // implementation at the .cpp
};

class B {
public:
    void FooFunctionOfB( float, float );
}

正如您所看到的,我想将指针保存到成员m_b的函数中,并将其调用为FooFunction。有了自己的功能(FooFunctionOfA())我已经成功了,但另一个更难。我尝试了几个想法,但我找不到编译器接受的版本。 :)

我发现了一个类似的问题,解决方案看起来像这样:&m_b.*m_b.FooFunctionOfB,此时我放弃了。

如果有人有任何想法,请不要犹豫与我分享。

我使用的是C ++而不是C ++ 0x而且我被迫避免使用stl和boost。

3 个答案:

答案 0 :(得分:4)

您需要使用std::tr1::function。此课程是为您所需的目的而构建的。它可以接受任何功能,成员功能等。

class A {
public:
    std::tr1::function<void(float, float)> m_fooFunction;
    B m_b;

    A( WhichUseEnum algorithm ) : m_b( B() )
    {
        switch( algorithm ) {
        case ALG_A:
            m_fooFunction = std::tr1::bind(&A::FooFunctionOfA, this);
            break;
        case ALG_B:
            m_fooFunction = std::tr1::bind(&A::FooFunctionOfA, &m_b);
            break;
        }
    }

    void FooFunction( float a , float b)
    {
         m_fooFunction( a, b );
    }

    void FooFunctionOfA( float, float ); // implementation at the .cpp
};

class B {
public:
    void FooFunctionOfB( float, float );
}

这里我使用std::tr1::bind来定义这两个函数。正如您所看到的,调用语法也更容易 - 就像常规函数调用一样。 std::tr1::bind除了成员函数和成员函数指针之外,还可以绑定更多。 Gah,已经有一段时间了,因为我不得不使用bind而不是lambdas。

C ++的一般规则是,如果您正在使用函数指针或成员函数指针,并且您没有与某些旧代码接口,那么您几乎肯定做错了。这也不例外。如果您预先使用C ++ 0x,那么您可能需要bind它们,但这是关于它的。

如果您使用的编译器太旧,它甚至没有TR1 ,您可以使用Boost替换这些设施 - 它们是Boost标准化的,因此Boost等效功能和界面非常接近。

答案 1 :(得分:2)

您可以提供完成工作的包装函数。

#include "B.h"
class A {
public:
    typedef void ( A::*FooFunction )( float, float );
    A::FooFunction m_fooFunction;
    B m_b;

    A( WhichUseEnum algorithm ) : m_b( B() )
    {
        switch( algorithm ) {
        case ALG_A:
            m_fooFunction = &A::FooFunctionOfA;
            break;
        case ALG_B:
            m_fooFunction = &A::FooFunctionOfB;
            break;
        }
    }

    void FooFunction( float a , float b)
    {
         ( this->*m_fooFunction )( a, b );
    }

    void FooFunctionOfA( float, float ); // implementation at the .cpp

    // A wrapper function that redirects the call to B::fooFunctionOfB().  
    void FooFunctionOfB( float a, float b)
    {
       this->m_b.FooFunctionOfB(a, b);
    }
};

class B {
public:
    void FooFunctionOfB( float, float );
}

答案 2 :(得分:-2)

你应该做什么:

(1)在原始算法上提取接口。现在,原始算法是此虚拟接口的实现。

class FooFunctionInterface
{
public:
    virtual void Foo(float a, float b) = 0;
};

class OriginalFoo : public FooFunctionInterface
{
public:
    void Foo(float a, float b) override
    {
       /* ... original implementation ... */
    }
};

(2)引入新算法作为接口的替代实现。

class NewFoo : public FooFunctionInterface
{
public:
    void Foo(float a, float b) override
    {
      /* ... new implementation ... */
    }
};

(3)引入工厂函数来选择要使用的实现。

class NullFoo : FooFunctionInterface
{
public:
    void Foo(float a, float b) override {}
};

std::unique_ptr<FooFunctionInterface> FooFactory(WhichUseEnum which)
{
    std::unique_ptr<FooFunctionInterface> algorithm(new NullFoo());

    switch(which)
    {
    case ALG_A: algorithm.reset(new OriginalFoo()); break;
    case ALG_B: algorithm.reset(new NewFoo()); break;
    };

    return algorithm;
}

然后你的A类成为pimpl成语转发调用到适当的实现。

class A
{
public:
      A(WhichUseEnum which) 
          : pimpl_(FooFactory(which))
      {
      }

      void Foo(float a, float b)
      {
         pimpl_->Foo(a, b);
      }

private:
      std::unique_ptr<FooFunctionInterface> pimpl_;
};

对你所造成的混乱采取极为清晰的方法。当您考虑在需要添加第三个实现,然后是第四个实现时将会发生什么,您就知道它更干净了。

在我的示例中,您扩展了工厂功能并继续您的生活。没有其他代码更改。