一、Forwarders的基础概念
在C++中,为了避免代码重复,我们会使用函数指针、虚函数等来实现代码的复用。然而,对于一些比较复杂的应用,这种方式仍然相对繁琐且易错。而在这种情况下,Forwarders就可以起到强有力的作用:它可以在一些对象之间建立联系,从而将对象与该对象下面的所有函数之间相连。 我们使用Forwarders的主要目的,在于实现除去接口的抽象化代码。举个例子,如果之前我们的强制类型转换与函数名的供养方式存在冲突,则我们可以采用以下的解决方案:
class MyClass
{
public:
int doSomething(double x)
{
cout << "in MyClass::doSomething(" << x << ")" << endl;
return(int)x;
}
};
class YourClass
{
public:
int doit()
{
typedef int (MyClass::*pmf_type)(double);
pmf_type pmf = &MyClass::doSomething;
MyClass mc;
int result = (mc.*pmf)(3.14);
cout << "result = " << result << endl;
return result;
}
};
而现在,我们只需要使用一个typename参数即可实现。
template<typename T, typename R, typename... Args>
class Forwarder
{
public:
Forwarder(R (T::*pmf)(Args...))
: pmf(pmf) {}
R Call(T* Object, Args... args)
{ return (Object->*pmf)(args...); }
private:
R (T::*pmf)(Args...);
};
struct MyClass
{
int DoSomething(double x)
{ return(x); }
};
struct YourClass
{
Forwarder<MyClass, int, double> f2{&MyClass::DoSomething};
int callDoSomething(MyClass* p, double x)
{
return f2.Call(p,x);
}
};
值得注意的是,对于嵌套类定义(如MyClass::*)来说,我们需要在参数表中进行一个小小的变形,即使用typedef进行访问,而非直接访问。
二、Forwarders的操作与实现
除了以上简单的应用外,Forwarders还可以拥有更加广泛的应用场景。比如说,在某个函数的传递过程中,如果该函数拥有过多参数,则可以令其使用Forwarders处理参数。 在此时,我们需要令该指针指向一个Forwarder类对象。这个操作看起来比较困难,但实际上代码的实现非常简单,如下所示:
template<typename... Args>
class Function
{
public:
typedef std::function<void(Args...)> HandlerType;
void operator+=( HandlerType h )
{
handlers.push_back( h );
}
void operator()( Args... args ) const
{
for( auto& handler : handlers )
handler( args... );
}
private:
std::vector<HandlerType> handlers;
};
template<typename T, typename R, typename... Args>
class Forwarder
{
public:
Forwarder(R (T::*pmf)(Args...))
: pmf(pmf) {}
R Call(T* Object, Args... args)
{ return (Object->*pmf)(args...); }
operator typename Function<Args...>::HandlerType()
{
return [&](Args... args)
{ Call(object, args...); };
}
private:
T* object;
R (T::*pmf)(Args...);
};
在这段代码中,我们首先定义了一个Function类,它能够编写抽象化函数,并在不同的对象之间建立联系。而在Forwarder的实现中,我们需要在里面编写一个左移运算符,将该对象的类型转化为Function类的HandlerType类型即可。
三、Forwarders的注意事项与用途分析
在编写回调函数或者说Adapters函数过程中,我们需要对Forwarders进行左移运算符的操作,而同样需要一定的规范来进行操作。 正如上文所述,我们可以使用Function类和Forwarder类将两个不同的类之间联系起来,实现类的接口化。同时,我们还需要注意构造函数中的typename之间的顺序。 但需要注意的是,虽然Forwarders具有很强的抽象化原则,不过我们在进行实际操作时,还需要考虑它的数据类型转换问题。因为Forwarders会在代码实现中进行许多样式和指针类型的转化,如果不加入安全校验的话,该方案存在许多隐患。
四、Forwarders的优缺点分析
Forwarders在代码的复用以及模板代码的高效展示方面,都具有一定的优势。然而,由于其调用过程较为繁琐,不太容易被用户接受。同时,在数据类型安全方面,它还存在一些潜在的问题。 总体来说,在解决抽象化代码问题以及模板的展示方面,Forwarders具有不可忽视的作用。只不过,对于安全性和程序效率等问题,我们需要在使用的时候进行一定的权衡和考虑。