我不确定这是不是一个愚蠢的问题,所以如果是的话就开枪吧!
我正经常遇到这种“困境”。我在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
}
其中 A 和 B 是不同的类型, G1 和 G2 是执行不同操作的不同功能。除 G1 和 G2 行之外的重载的代码部分是相同的,它们有时非常冗长。现在问题是..如何更有效地编写代码。当然,我不想重复代码(即使它很容易做到这一点,因为它只是一个复制粘贴例程)。一位朋友建议宏......但那看起来很脏。这很简单,因为如果我现在知道它是非常愚蠢的。非常感谢任何建议/帮助。
修改:对于那些想要代码示例的人,我很抱歉。这个问题实际上是抽象的,因为我遇到了不同的“相似”情况,我问自己如何使代码更短/更清洁。在大多数情况下代码很长,否则我不会在第一时间问这个问题。正如KilianDS指出的那样,确保函数本身不是很长也是很好的。但有时候这是不可避免的。在我遇到这种情况的许多情况下,循环甚至是嵌套的(即彼此之间的几个循环)和 F 的开头我们有一个循环的开始和 F 我们结束那个循环。
何塞
答案 0 :(得分:7)
在这种情况下,防止代码重复的一种简单方法是使用模板。 E.g:
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
函数如何用于确定是调用G1
还是G2
。
但是,请注意,这只会阻止代码重复,而不是编译的可执行文件中的重复(因为每个模板实例化都会创建自己的代码)。
根据周围的体系结构,可能还有许多其他可行的选项(例如虚拟方法而不是G1 / G2调用,函数指针,lambda函数,如果你有C ++ 11 ......)
答案 1 :(得分: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();
}
你需要转发构造函数使它有点罗嗦, 但它确实保持了所有常用代码的共同点。