2010-07-06 46 views
2

我有一个默认的int&参数(如iNewArgument)在头文件添加到现有的函数定义:如何使用带有默认值的int&参数?

什么是初始化的最后一个参数,使其取默认值的语法?

.. 
virtual int ExecNew 
    (int& param1, int& RowIn,int& RowOut, char* Msg = '0', 
      bool bDebug=true, int& iNewArgument = NULL) = 0 ; 
. 
. 

NULL已经#defined 0

Error: default argument: cannot convert from int to int&

+3

如果你希望它能够为null,那么你需要一个指针而不是引用。 – 2010-07-06 22:10:44

+0

我与迈克在这。请参阅[我的答案](http://stackoverflow.com/questions/3190571/c-int-reference-question/3190603#3190603)。 – sbi 2010-07-06 22:18:58

+0

我拿回来(我删除了我的答案)。除了约翰尼斯,每个人都忽略了“虚拟”。为虚拟函数设置默认参数并不是一个好主意。 – sbi 2010-07-06 22:29:46

回答

9

你的例子表明你正在创建一个虚函数。虚拟(特别是纯粹)函数中的默认参数不是一个好主意,因为在调用重写函数时不会考虑它们。现在

struct A { 
    virtual void f(int = 4711) = 0; 
}; 

struct B : A { 
    virtual void f(int) { /* ... */ } 
}; 

,如果有人一B对象调用f,他将提供的说法 - 不使用默认值。您必须在派生类中重复默认参数,这会产生丑陋的冗余。相反,你可以使用非虚拟接口模式

struct A { 
    void f(int a) { 
    int out; 
    f(a, out); 
    } 

    void f(int a, int &out) { 
    doF(a, out); 
    } 

protected: 
    virtual void doF(int a, int out&) = 0; 
}; 

用户现在可以用一个叫f,并有两个参数,无论从任何类类型他所说的功能,和A实施者没有担心默认的参数。通过使用重载而不是默认参数,你不需要围绕左值或临时值。

+0

哦,大家都忽略了这个!好,赶上,约翰内斯,'+ 1'从我身上。 (而且,顺便说一句,如果'B :: f()'有一个不同的默认参数,它会更加严重 - 代码默默编译,但是具有不同的语义! – sbi 2010-07-06 22:27:46

1

你不能做到这一点。 INewArgument必须是一个原始int或一个const引用。无法以您尝试使用它的方式使用非const引用。

1

总之,你将不得不重做你的问题。你可以使int成为一个常规的int并且失去参考行为(能够传递改变的值)或者放弃具有默认值。

+0

再次查看您的示例代码,您正在尝试使用INewArgument传递一个指针,而不是引用。在这种情况下,这是您的另一种选择:传递一个指针而不是引用。如果你不介意使用指针,它会很好用。 – 2010-07-06 22:12:31

1

对于非const引用类型,缺省值必须是左值,所以上面的尝试不起作用。你可以做的是:

namespace detail { 
    int global; 
} 

void foo(int &x = detail::global) {} 

void bar(const int &x = int(3)) {} 
+0

对于你的第一种情况:'NULL'作为“我没有你的参数”是普遍理解的,'detail :: global'不是。对于第二种情况:应该对每个副本采用内置插件,而不是每个“const”引用。 – sbi 2010-07-06 22:25:07

+0

第二个变体对于更复杂的数据类型仍然有用,例如void foo(const std :: set &x = std :: set ()),这有时是有道理的。 – Staffan 2010-07-06 22:29:05

4

提供一个默认的参数传递给一个非const引用的唯一有意义的方法是定义一个独立的对象具有静态存储时间和使用它作为默认参数

int dummy = 0; 

... 
virtual int ExecNew(/* whatever */, int& iNewArgument = dummy) = 0; 

它是否会为您工作是由您来决定。

在函数内部,如果你需要检测是否使用了默认参数,你可以使用地址比较

if (&iNewArgument == &dummy) 
    /* Default argument was used */ 
+0

如果在函数内部比较地址,那么这表示函数应该为每个引用取这个对象。如果地址对函数的语义很重要,则调用者应该可以看到它。 – sbi 2010-07-06 22:21:26

+0

@sbi:在这种特殊情况下,地址被视为一个没有接口含义的实现细节。将该实现细节公开给用户是不正确的。然而,我只是补充说,在最好的情况下,应该选择默认参数,以便(函数被设计成使得)函数不需要检测已经使用了默认参数的事实。 – AnT 2010-07-06 22:30:50

1

你说NULL是#defined为0,所以这是一个文字值。该参数是对int的引用,这意味着该函数将能够更改该值。你如何改变文字的价值?

您需要将其作为const参考,或者根本不要将其作为参考。