使用类属性值作为方法默认参数的替代方法?
Posted
技术标签:
【中文标题】使用类属性值作为方法默认参数的替代方法?【英文标题】:Alternatives to using class attribute value as a method default parameter? 【发布时间】:2012-03-13 22:47:02 【问题描述】:我想实现这样的目标:
class C
int m_nVal;
public:
C(int nVal) : m_nVal(nVal)
void foo(int nVal = m_nVal)
// use nVal, if provided; otherwise use m_nVal
;
C c(1);
c.foo(); // use 1
c.foo(2); // use 2
正如 C++ 标准所说,这是不可能的:
不应在默认参数中使用非静态成员
我的选择是:
(1) 重载foo()
:
class C
int m_nVal;
public:
C(int nVal) : m_nVal(nVal)
void foo()
// use m_nVal
void foo(int nVal)
// use nVal
;
(2) 使用静态成员:
class C
static int m_nVal;
public:
void foo(int nVal = m_nVal)
// use nVal, if provided; otherwise use m_nVal
;
我不想让m_nVal
成为静态成员,所以选项 1 似乎是唯一的一个。
还有其他方法可以实现吗?
【问题讨论】:
可以说这就是为设计的重载。 只调用 foo() 就 foo(int nval); 我猜不能选择使用指针和nullptr
作为默认值?
【参考方案1】:
如果您愿意更改界面,还有其他选择。你可以使用boost::optional
:
// untested:
void foo( boost::optional<int> val = boost::optional<int>() )
int value;
if ( val ) value = *val;
else value = m_val;
// Now use `value` in the function
如果您不能使用 boost,您可以编写自己的可空包装器。您只需要存储类型 (int
) 和一个确定是否设置的标志。
下一个选项是使用指针来标记参数是可选的:
void foo( int *pval = 0 )
int value = (pval? *pval : m_val);
// use value from here on
但是带有指针的选项禁止使用 rvalues 作为函数的参数(即你需要一个适当的变量来调用函数,你不能做foo(1)
,而是需要做@ 987654326@,有点痛苦)。
最后,您可以使用提供两个重载的方法,一个接受参数,一个不接受参数,只转发到第一个:
void foo( int val )
// actual implementation
void foo()
foo( m_val );
这实际上可能是最好的选择...
【讨论】:
不幸的是,Boost 不是选项(不是我的决定);我喜欢使用指针的想法,但是,正如您所说,这个接口对客户端来说看起来并不自然(传递指针而不是对象本身);我会选择重载。【参考方案2】:传递默认参数意味着编译器必须传递它。这意味着,对于m_nVal
,编译器将使用this->m_nVal
。反过来,这意味着 `foo(this->m_nVal);'。
这就是我的意思:
c.foo(c.m_nVal); // use 1
这将允许 m_nVal
private 数据在课堂外访问,并违反基本 C++ 规则。
【讨论】:
访问不是该构造的问题,因为您可以通过公开该字段来进行测试,在这种情况下授予访问权限但它也不会编译。 @Ajay 这实际上是我开始考虑重构代码的原因 -m_nVal
目前是公开的,我想隐藏它。另一件事是foo
最常以c.m_nVal
作为参数调用,所以我开始考虑将其用作默认值...
是的,但私有和受保护是不允许这样做的原因之一。【参考方案3】:
class C
int m_nVal;
public:
C(int nVal) : m_nVal(nVal)
void foo(int nVal = -1)
if(nVal == -1)
nVal = m_nVal;
// use nVal, if provided; otherwise use m_nVal
;
C c(1);
c.foo(); // use 1
c.foo(2); // use 2
【讨论】:
这太糟糕了,如果我想打电话给foo(-1)
怎么办?在你开始被否决之前,我会删除它。
我其实认为在很多你知道特定值无效的域中可以用作哨兵。例如,如果已知参数不是否定的,这将是一个选项。我也不会投赞成票,但 +1 以补偿根据域可能是一个选项。
@DavidRodríguez-dribeas 为什么不是参数unsigned int
?
@DavidRodríguez-dribeas 这是非常违反直觉的。想象一下文档:传递任何整数值。如果要使用成员 m_nVal
,请传递 -1
。 :|
这个想法很好,但就我而言,由于 Luchian 提到的原因,我不能依赖使用硬编码值。但感谢您的帮助。【参考方案4】:
这两个选项不等价。创建成员 static
不应该是您是否要将其用作方法的默认值的决定。
如果m_nVal
在逻辑上绑定到类,而不是实例,则将其设为static
。
如果m_nVal
特定于类的每个对象,请不要使用第一个选项。
【讨论】:
完全同意。static
从一开始就不是一个选择。我在上面列出它只是因为它解决了一般问题(但不是在某些不适合类设计的特殊情况下)。
@BojanKomazec 我会选择超载,其他一切对我来说似乎都是多余的。
是的,这似乎是最直观的方法。感谢您的帮助。以上是关于使用类属性值作为方法默认参数的替代方法?的主要内容,如果未能解决你的问题,请参考以下文章
PHP 使用 $this->variable 作为类方法参数默认值
使用 expando 元类添加 curried 闭包作为静态属性会丢失默认参数值