我有点复杂的情况。它可以很容易地通过继承来解决,但我现在很好奇,并且由于其他一些原因我会以这种方式解决它。
我有一个表示算法的类,并且随着时间的推移已经实现了不同的解决方案。目前,我有原班级,它的成员是新成员。 我会同时使用算法和开关来根据情况使用它们。
#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。
答案 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_;
};
对你所造成的混乱采取极为清晰的方法。当您考虑在需要添加第三个实现,然后是第四个实现时将会发生什么,您就知道它更干净了。
在我的示例中,您扩展了工厂功能并继续您的生活。没有其他代码更改。