先看看该链接讨论的问题作为热身。http://topic.csdn.net/u/20070616/13/2a6a1739-1a69-4829-a90f-fdb19a61e095.html
函数返回值和返回引用是不同的
函数返回值时会产生一个临时变量作为函数返回值的副本,而返回引用时不会产生值的副本,既然是引用,那引用谁呢?这个问题必须清楚,否则将无法理解返回引用到底是个什么概念。以下是几种引用情况:
1,引用函数的参数,当然该参数也是一个引用
const string &shorterString(const string &s1,const string &s2)
{
return s1.size()
以上函数的返回值是引用类型。无论返回s1或是s2,调用函数和返回结果时,都没有复制这些string对象。简单的说,返回的引用是函数的参数s1或s2,同样s1和s2也是引用,而不是在函数体内产生的。函数体内局部对象是不能被因哟个的,因为函数调用完局部对象会被释放。
2,千万不要返回局部对象的引用
const string &mainip(const string &s)
{
string ret=s;
return ret;
}
当函数执行完毕,程序将释放分配给局部对象的存储空间。此时,对局部对象的引用就会指向不确定的内存。
3,在类的成员函数中,返回引用的类对象,当然不能是函数内定义的类对象(会释放掉),一般为this指向的对象,典型的例子是string类的赋值函数。
这与sting类中的“+”运算符重载不一样。“+”运算符的重载不能返回引用,因为它返回的是在函数内定义的类对象,附上代码。
4,引用返回左值(上例的=赋值也是如此,即a=b=c是可以的)
char &get_val(string &str,string::size_type ix)
{
return str[ix];
}
使用语句调用:
string s("123456");
cout< get_val(s,0)='a';
cout<
最后转上一段code作为总结。
//////////////////////////////////////////////函数返回值//////////////////////////////////////////////////////////////////////////////////
不带返回值的 return 语句只能用于返回类型为 void 的函数。在返回类型为 void 的函数中,return 返回语句不是必需的,隐式的 return 发生在函数的最后一个语句完成时。
一般情况下,返回类型是 void 的函数使用 return 语句是为了引起函数的强制结束,这种 return 的用法类似于循环结构中的 break 语句的作用。例如,可如下重写 swap 程序,使之在输入的两个数值相同时不执行任何工作:
// ok: swap acts on references to its arguments
void swap(int &v1, int &v2)
{
// if values already the same, no need to swap, just return
if (v1 == v2)
return;
// ok, have work to do
int tmp = v2;
v2 = v1;
v1 = tmp;
// no explicit return necessary
}
这个函数首先检查两个值是否相等,如果相等则退出函数;如果不相等,则交换这两个值,隐式的 return 发生在最后一个赋值语句后。
返回类型为 void 的函数通常不能使用第二种形式的 return 语句,但是,它可以返回另一个返回类型同样是 void 的函数的调用结果:
void do_swap(int &v1, int &v2)
{
int tmp = v2;
v2 = v1;
v1 = tmp;
// ok: void function doesn't need an explicit return
}
void swap(int &v1, int &v2)
{
if (v1 == v2)
return false; // error: void function cannot return a value
return do_swap(v1, v2); // ok: returns call to a void function
}
返回任何其他表达式的尝试都会导致编译时的错误。
返回类型不是 void 的函数必须返回一个值,但此规则有一个例外情况:允许主函数 main 没有返回值就可结束。如果程序控制执行到主函数 main 的最后一个语句都还没有返回,那么编译器会隐式地插入返回 0 的语句。
关于主函数 main 返回的另一个特别之处在于如何处理它的返回值。可将主函数 main 返回的值视为状态指示器。返回 0 表示程序运行成功,其他大部分返回值则表示失败。非 0 返回值的意义因机器不同而不同,为了使返回值独立于机器,cstdlib 头文件定义了两个预处理变量,分别用于表示程序运行成功和失败:
#include
int main()
{
if (some_failure)
return EXIT_FAILURE;
else
return EXIT_SUCCESS;
}
我们的代码不再需要使用那些依赖于机器的精确返回值。相应地,这些值都在 cstdlib 库中定义,我们的代码不需要做任何修改。
函数的返回值用于初始化在调用函数处创建的临时对象。在求解表达式时,如果需要一个地方储存其运算结果,编译器会创建一个没有命名的对象,这就是临时对象。在英语中,C++ 程序员通常用 temporary 这个术语来代替 temporary object。
用函数返回值初始化临时对象与用实参初始化形参的方法是一样的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。当函数返回非引用类型时,其返回值既可以是局部对象,也可以是求解表达式的结果。
例如,下面的程序提供了一个计数器、一个单词 word 和单词结束字符串 ending,当计数器的值大于 1 时,返回该单词的复数版本:
// return plural version of word if ctr isn't 1
string make_plural(size_t ctr, const string &word,
const string &ending)
{
return (ctr == 1) ? word : word + ending;
}
这个函数要么返回其形参 word 的副本,要么返回一个未命名的临时 string 对象,这个临时对象是由字符串 word 和 ending 的相加而产生的。这两种情况下,return 都在调用该函数的地方复制了返回的 string 对象。
当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。例如,考虑下面的函数,此函数返回两个 string 类型形参中较短的那个字符串的引用:
// find longer of two strings
const string &shorterString(const string &s1, const string &s2)
{
return s1.size() < s2.size() ? s1 : s2;
}
形参和返回类型都是指向 const string 对象的引用,调用函数和返回结果时,都没有复制这些 string 对象。
注意:千万不能返回局部变量的引用,同理,也不能返回指向局部变量的指针。
当函数执行完毕时,将释放分配给局部对象的存储空间。此时,对局部对象的引用就会指向不确定的内存。考虑下面的程序:
// Disaster: Function returns a reference to a local object
const string &manip(const string& s)
{
string ret = s;
// transform ret in some way
return ret; // Wrong: Returning reference to a local object!
}
这个函数会在运行时出错,因为它返回了局部对象的引用。当函数执行完毕,字符串 ret 占用的储存空间被释放,函数返回值指向了对于这个程序来说不再有效的内存空间。
返回引用的函数返回一个左值。因此,这样的函数可用于任何要求使用左值的地方:
char &get_val(string &str, string::size_type ix)
{
return str[ix];
}
int main()
{
string s("a value");
cout << s << endl; // prints a value
get_val(s, 0) = 'A'; // changes s[0] to A
cout << s << endl; // prints A value
return 0;
}
给函数返回值赋值可能让人惊讶,由于函数返回的是一个引用,因此这是正确的,该引用是被返回元素的同义词。
如果不希望引用返回值被修改,返回值应该声明为 const:
const char &get_val(...
传值时就是在内存中新开辟一个空间,将值赋给这个新开辟的空间,其生命周期为该函数调用结束时释放该空闲,计算结果不影响原调用数据内存空间的值。 传址时同样新开辟一个空间,但不同的是将所用数据空间的内存地址存在新开辟的空间中,即指针,函数在数据处理过程中由于是指针,即对源数据进行操作,操作后结果影响原数据。
打个比喻,一个盒子里有一个苹果,传值就是把这个苹果复制成另外一个苹果给要传的对象,至于这个对象怎么弄复制的苹果跟原来的那个没关系,而传值则是把盒子给了这个对象,那么这个对象要把这里面的苹果怎么弄那这个苹果就要改变,