在C ++中通过引用传递参数时的默认值
当我们通过引用传递参数时,是否有可能给函数的参数赋予默认值? 在C ++中
例如,当我尝试声明一个如下的函数:
virtual const ULONG Write(ULONG &State = 0, bool sequence = true);
当我这样做的时候会给出一个错误:
错误C2440:'默认参数':不能从'const int'转换为'unsigned long'不是'const'的引用不能绑定到一个非左值
你可以做一个const引用,但不是一个非const的引用。 这是因为C ++不允许将临时(在这种情况下为默认值)绑定到非const引用。
其中一种方法是使用实际的实例作为默认实例:
static int AVAL = 1; void f( int & x = AVAL ) { // stuff } int main() { f(); // equivalent to f(AVAL); }
但这是非常有限的实际使用。
有人在你的回答中直接提出了一个意见,但只是正式表态。 你想要使用的是一个重载:
virtual const ULONG Write(ULONG &State, bool sequence); inline const ULONG Write() { ULONG state; bool sequence = true; Write (state, sequence); }
使用函数重载也有其他好处。 首先你可以默认你想要的任何参数:
class A {}; class B {}; class C {}; void foo (A const &, B const &, C const &); void foo (B const &, C const &); // A defaulted void foo (A const &, C const &); // B defaulted void foo (C const &); // A & B defaulted etc...
也可以重新定义派生类中的虚函数的默认参数,这种重载避免了:
class Base { public: virtual void f1 (int i = 0); // default '0' virtual void f2 (int); inline void f2 () { f2(0); // equivalent to default of '0' } }; class Derived : public Base{ public: virtual void f1 (int i = 10); // default '10' using Base::f2; virtual void f2 (int); }; void bar () { Derived d; Base & b (d); d.f1 (); // '10' used b.f1 (); // '0' used d.f2 (); // f1(int) called with '0' b.f2 (); // f1(int) called with '0 }
只有一种情况需要使用默认值,这是一个构造函数。 从另一个构造函数中调用是不可能的,所以这种方法在这种情况下不起作用。
仍然有提供可选参数的旧C方法:当不存在时可以为NULL的指针:
void write( int *optional = 0 ) { if (optional) *optional = 5; }
这个小模板将帮助你:
template<typename T> class ByRef { public: ByRef() { } ByRef(const T value) : mValue(value) { } operator T&() const { return((T&)mValue); } private: T mValue; };
那么你将能够:
virtual const ULONG Write(ULONG &State = ByRef<ULONG>(0), bool sequence = true);
对于默认参数,您不能使用常量常量,因为您不能将其用作函数调用的参数。 参考值必须有一个地址,常量引用值不需要(即它们可以是r值或常量文字)。
int* foo (int& i ) { return &i; } foo(0); // compiler error. const int* bar ( const int& i ) { return &i; } bar(0); // ok.
确保你的默认值有一个地址,你很好。
int null_object = 0; int Write(int &state = null_object, bool sequence = true) { if( &state == &null_object ) { // called with default paramter return sequence? 1: rand(); } else { // called with user parameter state += sequence? 1: rand(); return state; } }
我已经使用了这个模式几次,我有一个参数可能是一个variables或null。 常规的做法是让用户传入一个指针。 如果他们不希望你填写值,他们传递一个NULL指针。 我喜欢null对象的方法。 它使呼叫者的生活更轻松,而不会使被调用者的代码复杂化。
有两个理由通过引用传递参数:(1)性能(在这种情况下,你想通过const引用)和(2),因为你需要能够改变函数内的参数的值。
我非常怀疑,在现代架构上通过一个无符号的长度会让你失望太多。 所以我假设你打算改变方法内部的State
值。 编译器抱怨是因为常数0
不能被改变,因为它是一个右值(错误消息中的“非左值”),并且不可更改(错误消息中的const
)。
简而言之,你需要一个可以改变parameter passing的方法,但是默认情况下你想传递一个不能改变的参数。
换句话说,非const
引用必须引用实际variables。 函数签名( 0
)中的默认值不是一个实数variables。 你遇到了同样的问题:
struct Foo { virtual ULONG Write(ULONG& State, bool sequence = true); }; Foo f; ULONG s = 5; f.Write(s); // perfectly OK, because s is a real variable f.Write(0); // compiler error, 0 is not a real variable // if the value of 0 were changed in the function, // I would have no way to refer to the new value
如果你实际上并没有打算改变State
,你可以简单地把它改成一个const ULONG&
。 但是你不会从中获得巨大的性能收益,所以我build议将其改为非参考ULONG
。 我注意到你已经返回了一个ULONG
,我有一个鬼鬼祟祟的怀疑,它的价值是任何需要修改后的State
的价值。 在这种情况下,我只是简单地声明这个方法:
// returns value of State virtual ULONG Write(ULONG State = 0, bool sequence = true);
当然,我不太清楚你在写什么或在哪里。 但这又是另外一个问题了。
不,这是不可能的。
按引用传递意味着函数可能会改变参数的值。 如果参数不是由调用者提供的并且来自默认常量,那么该函数应该改变什么?
我认为不是,原因是默认值被评估为常量和引用传递的值必须能够改变,除非你也声明它是常量引用。
另一种方式可能如下:
virtual const ULONG Write(ULONG &State, bool sequence = true); // wrapper const ULONG Write(bool sequence = true) { ULONG dummy; return Write(dummy, sequence); }
那么下面的调用是可能的:
ULONG State; object->Write(State, false); // sequence is false, "returns" State object->Write(State); // assumes sequence = true, "returns" State object->Write(false); // sequence is false, no "return" object->Write(); // assumes sequence = true, no "return"
void f(const double& v = *(double*) NULL) { if (&v == NULL) cout << "default" << endl; else cout << "other " << v << endl; }
在OO的情况下…要说一个给定的类具有和“默认”意味着这个默认(值)必须申明一个然后可以被用作一个默认参数例如:
class Pagination { public: int currentPage; //... Pagination() { currentPage = 1; //... } // your Default Pagination static Pagination& Default() { static Pagination pag; return pag; } };
在你的方法…
shared_ptr<vector<Auditoria> > findByFilter(Auditoria& audit, Pagination& pagination = Pagination::Default() ) {
这种解决scheme非常合适,因为在这种情况下,“全局默认分页”是一个单一的“参考”值。 您还将有权在运行时更改默认值,如“gobal-level”configuration,如:用户分页导航首选项等。
这是可能的const限定符的状态:
virtual const ULONG Write(const ULONG &State = 0, bool sequence = true);
void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false);
这也是一个相当脏的伎俩:
virtual const ULONG Write(ULONG &&State = 0, bool sequence = true);
在这种情况下,你必须用std::move
来调用它:
ULONG val = 0; Write(std::move(val));
这只是一个有趣的解决方法,我完全不build议使用真正的代码!
虚拟常量ULONG写(ULONG&状态= 0,布尔序列=真);
答案是相当简单的,我不是很好的解释,但如果你想传递一个默认值的非常量参数,可能会被修改在这个函数是这样使用它:
virtual const ULONG Write(ULONG &State = *(ULONG*)0, bool sequence = > true);