繁体   English   中英

成员函数的函数指针

[英]Pointer to function from a member's function

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

我有代表算法的课程,随着时间的推移,已经实现了不同的解决方案。 目前,我拥有原始班级,并且它的成员是新班级。 我将同时拥有算法和开关,以便能够根据情况使用它们。

#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。

您需要使用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而不是lambda。

C ++的一般规则是,如果您使用函数指针或成员函数指针,并且没有与某些旧代码交互,则几乎可以肯定它做错了。 也不例外。 如果您使用的是C ++ 0x之前的版本,则可能也需要bind它们,仅此而已。

如果您使用的编译器太旧了, 甚至没有TR1 ,则可以使用Boost来替代这些功能-它们是Boost的Standardized,因此Boost的等效功能和接口都非常接近。

您可以提供一个完成该任务的包装函数。

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

您应该做什么:

(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_;
};

大大简化了您造成的混乱。 当您考虑需要添加第三个实现,然后添加第四个实现时,会发生什么,就知道它的清除器。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM