1

我不确定这是否是一个愚蠢的问题,如果是,请向我射击!

我经常遇到这种“困境”。我在 C++ 中说过两个重载函数

假设我们有这两个F重载(只是下面的伪代码)

void F(A a, .../*some other parameters*/)
{ 
  //some code part
  //loop Starts here
  G1(a,.../* some other parameter*/)
  //loop ends here
  //some code part
}


void F(B b, .../*some other parameters*/)
{
  //some code part
  //loop Starts here
  G2(b,.../* some other parameter*/)
  //loop ends here
  //some code part
}

其中AB是不同的类型,G1G2是做不同事情的不同功能。除了G1G2行之外,重载的代码部分是相同的,而且它们有时非常长且广泛。现在的问题是.. 我怎样才能更有效地编写我的代码。自然,我不想重复代码(即使这样做很容易,因为它只是一个复制粘贴例程)。一位朋友建议使用宏……但这看起来很脏。这很简单吗,因为如果我现在知道是不是很愚蠢。将不胜感激任何建议/帮助。

编辑:我很抱歉那些想要一个代码示例的人。这个问题真的很抽象,因为我遇到了不同的“相似”情况,我问自己如何才能使代码更短/更清晰。在大多数情况下,代码很长,否则我不会一开始就问这个问题。正如 KilianDS 所指出的,确保函数本身不是很长也很好。但有时这只是不可避免的。在我遇到这种情况的许多情况下,循环甚至是嵌套的(即相互之间有几个循环),并且F的开头是循环的开始,而F的结尾是循环的结束。

何塞

4

2 回答 2

7

在这种情况下,防止代码重复的一种简单方法是使用模板。例如:

void G(A a,.../* some other parameter*/)
{
    G1(a,.../* some other parameter*/);
}
void G(B b,.../* some other parameter*/)
{
    G2(b,.../* some other parameter*/);
}

template <typename T>
void F(T x, .../*some other parameters*/)
{ 
  //some code part
  //loop Starts here
  G(x,.../* some other parameter*/)
  //loop ends here
  //some code part
}

请注意如何使用重载G函数来确定是否调用G1G2。但是,还要注意这只能防止代码重复,而不是编译的可执行文件中的重复(因为每个模板实例化都会创建自己的代码)。

根据周围的架构,可能还有许多其他可行的选项(例如,虚拟方法而不是 G1/G2 调用、函数指针、lambda 函数,如果你有 C++11...)

于 2012-10-23T09:42:18.570 回答
3

最明显的解决方案是将公共代码部分放入单独的函数中,并调用它们:

void F( A a, ... )
{
    commonPrefix(...);
    G1( a, ... );
    commonPostfix(...);
}

void F( B b, ... )
{
    commonPrefix(...);
    G2( a, ... );
    commonPostfix(...);
}

如果前缀和后缀之间共享大量数据,您可以创建一个类来保存它,并使函数成为成员。

或者,您可以转发到模板,可能使用特征:

template <typename T>
class GTraits;

template<>
class GTraits<A>
{
    static void doG( A a, ... ) { G1( a, ... ); }
};

template <>
class GTraits<B>
{
    static void doG( B b, ... ) { G2( b, ... ): }
};

template <typename T>
void doF( T t, ... )
{
    //  ...
    GTraits<T>::doG( t, ... );
    //  ...
}

void F(A a, ...)
{
    doF( a, ... );
}

void F(B b, ...)
{
    doF( b, ... );
}

然而,这很容易导致代码的公共部分被复制。(这是否是一个问题取决于。在大多数情况下,我怀疑代码膨胀是最小的。)

编辑:

既然您说通用代码包含循环逻辑:您可以使用模板方法模式,例如:

class CommonBase
{
    virtual void doG( other_params ) = 0;
public:
    void doF()
    {
        //  prefix
        //  loop start
        doG( other_params );
        //  loop end
        //  suffix
    }
};

然后在每个函数中定义一个单独的派生类:

void F( A a ,... )
{
    class DoG : public CommonBase
    {
        A myA;
        void doG( other_params ) { G1( myA, other_params ); }
    public:
        DoG( A a ) : myA( a ) {}
    } do( a );
    do.doF();
}

您需要转发构造函数这一事实使它有点罗嗦,但它确实使所有通用代码保持通用。

于 2012-10-23T10:12:25.233 回答