class X {
X(int, int); //constructor
void func();
}
class Y {
public int func() {
X x(5,7);
// some other random operations.
x.func();
}
}
现在,如果我必须根据某些条件初始化x,我该怎么做?
class Z {
// only refer to x when mycond is true.
public int func(boolean mycond) {
if(mycond)
X x(5,7);
//same random operations;
if(mycond)
x.func();
}
}
以不美观的方式完成上述工作的一种方法是:
class Z {
// only refer to x when mycond is true.
public int func(boolean mycond) {
if(mycond) {
X x(5,7);
//same random operations;
x.func();
}
else {
//same random operations
}
}
}
我正在寻找更简单的东西,我不必重复代码。
答案 0 :(得分:4)
在你给出的例子中,不清楚为什么你不能把它写成:
class Z {
// only refer to x when mycond is true.
public:
int func(bool mycond) {
//same random operations;
if(mycond) {
X x(5,7);
x.func();
}
}
};
但是,如果由于某种原因这是不可取的(例如,如果X
的构造函数有一些必须在“某些随机操作”之前发生的副作用),那么你应该看看{{1} }:
boost::optional
如果由于某种原因您不想使用class Z {
// only refer to x when mycond is true.
public:
int func(bool mycond) {
boost::optional<X> x;
if (mycond) x = X(5,7);
//some random operations;
if (mycond) x->func();
}
};
,那么使用boost::optional
可以获得类似的效果:
union
也就是说,这将导致将名称引入范围,其中该名称有时仅具有意义。这是非常值得怀疑的,你应该考虑使用不同的设计。
答案 1 :(得分:2)
显而易见的答案是将其他随机操作放在一个单独的操作中 功能,所以你的代码变成:
int
func()
{
if ( myCondition ) {
X x( 5, 7 );
otherOperations();
x.func();
} else {
otherOperations();
}
}
无论如何,你应该这样做,如果只是为了完成这个功能 可读和可维护。
答案 2 :(得分:1)
显而易见的解决方案是使用指针或自动指针:
class Z {
public:
// only refer to x when mycond is true.
int func(boolean mycond) {
std::auto_ptr<X> px;
if(mycond)
px = new X(5,7);
//same random operations;
if (px.get() != 0)
px->func();
}
}
答案 3 :(得分:0)
您可以将“随机操作”分解出来,就像这样
if (my_cond) X x(5, 7);
random_operations_factored_out(T& a, U& b, const W& c, ..); // all the references that you need
if (my_cond) X.func();
显然你可以(应该?)更好地封装上下文,为了一个例子,我使用了pass-by-reference。
另一种可能性是将逻辑封装在一对构造函数和析构函数中,如
class X_caller{
private:
bool cond;
X x;
public:
X_caller(bool cond, int param1, int param2):cond(cond){
if (cond) {x = X(param1, param2);}
}
~X_caller(){
if (cond) x.func();
}
}
现在你将使用这个
{
X_caller(my_cond, 5, 7);
// all your operations
} // at the end of the scope the destructor of X_caller calls x.func() only if my_cond was true
// but you "can't see" this function call if you don't know the body of X_caller, so be careful!
// You have to document this kind of behaviour otherwise it's too obscure for future maintenance.
在所有情况下,您必须确保必须访问的所有资源(变量等)都可用于分解代码。
各种选择之间的平衡取决于代码的复杂性:总是尽量减少代码阅读器中的潜在混淆。这可能来自长时间重复的代码,或来自“隐藏”的调用或来自许多其他来源,如果可能,您应该尽量减少它。
答案 4 :(得分:0)
如何使用new
和pointer (*)
X *xPtr = 0;
class Z
{
// only refer to xPtr when mycond is true.
public int func(boolean mycond)
{
if(mycond)
{
xPtr = new X(5,7);
}
//same random operations;
if(xPtr)
{
xPtr.func();
}
}
// and don't forget delete xPtr;
}
并查看以上代码是否可以重构如下:
X *xPtr = 0;
class Z
{
// only refer to xPtr when mycond is true.
public int func(boolean mycond)
{
//same random operations;
if(mycond)
{
xPtr = new X(5,7);
xPtr.func();
}
}
// and don't forget delete xPtr;
}
答案 5 :(得分:0)
你的要求就是不重复某些事情,你可以使用空对象模式。
class Base
{
};
class X : public Base
{
};
class NullX : public Base
{
};
然后
int funX(boolean mycond) {
Base* p = NULL;
if (mycond)
p = new x(5,7);
else
p = new NullX;
//... some other
//if (mycond)
p->func();
}
然后我们可以删除第二个if语句。
而且,如果你的条件仅用于控制X,那么funX将是:
int funX (Base& x)
{
//some other
x.func();
}
并且mycondtion将是另一个函数,
Base* getBase(int mycond)
{
if (mycond)
return new X(5, 7);
return new NullX;
}
然后该函数将被完全重构。