使用类属性值作为方法默认参数的替代方法?

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-&gt;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 闭包作为静态属性会丢失默认参数值

如何在 Python 中使用类变量作为默认参数值

用不同的参数和默认值在 Ruby 中初始化类的最有效方法是啥?

使用类自变量作为默认类方法参数[重复]

Java基础学习笔记十二 类抽象类接口作为方法参数和返回值以及常用API