C++中返回类型与return语句

C++中返回类型与return语句

有、无返回值的函数及其return语句
无返回值(函数声明中,返回值类型为void)的函数,如果其中没有任何return语句也是正确的,编译器会自动在函数结束处补上隐式的return;语句。如果这种void函数内部出现显式的return;,其作用是表示该函数在此处将控制权交还给主调函数。
除void函数外,其他函数必须显式地返回与声明中返回值类型相同(或可以转换为该类型)的值。
函数把值返回给调用处的细节原理
函数把值返回给外部调用处的实现方法细节与从外部实参传递值给函数形参的方法细节完全一样。本质上是用已有值(传参中的实参,返回中的返回值)初始化一个临时量(传参中的形参,返回中的函数调用点)。因此对象的初始化规则在函数返回过程中仍然适用。

1 函数返回局部变量给外部
本质上是将函数内局部变量的值拷贝给函数调用点,用来初始化(外部)调用点的临时对象。

2 函数返回引用给外部
引用是对象的别名,因此此时函数对外返回的是对象本身,而不是拷贝一个值给外部副本。因此要特别注意,千万不能返回函数内部局部对象的引用和指针。因为函数在结束调用后局部变量就会被销毁,这时被函数给返回到外部的局部变量对象(引用)将不再绑定有效的内存区域。

综上可知,函数要想对外返回引用(或指针),只能返回那种在函数调用之前已经存在了的对象的引用(或指向该对象的指针)

范例:

//函数对外返回引用的正确用法
const string &shorterStr(const string &s1, const string &s2) { //挑出两个string对象中较短的那个,返回其引用
    return s1.size() <= s2.size() ? s1 : s2; //因为s1和s2绑定的对象都是在调用函数前就已经存在的了,因此函数对外返回这种对象的引用不会产生问题
}

//以下写法严重错误,这个函数试图返回局部对象的引用
const string &manip() {
    string ret;
    if (!ret.empty()) {
        return ret; //❌,试图返回局部对象的引用
    } else {
        return "Empty"; //❌,"Empty"也是一个局部临时量,并且以引用的方式传出,在函数结束调用后该临时量会被销毁,使得外部调用点的引用不再绑定具体对象
    }
}

//以下写法严重错误,不能返回一个指向局部对象的指针
int *funcIp(int var) {
    int i = 10;
    int *ip = &(i + var); //i + var对象是一个临时量,结束调用后销毁,对外返回的指针无法指向确定的内存
    return ip;
}

返回类类型的函数可以连续调用
返回类类型(类的对象或其引用,或指向类的对象的指针)的函数,可以在其调用处继续使用调用运算符去调用该类的其他函数,如下例:

const string &shorterStr(const string &s1, const string &s2) { //此函数返回的是一个string对象的引用
	return s1.size() <= s2.size() ? s1 : s2; 
}
string s1 = "aaaa";
string s2 = "bbb";
auto sz = shorterStr(s1, s2).size(); //shoterStr(s1, s2)返回的是一个string对象(s2),该对象有size()成员函数,因此可以在shoterStr()的返回处再继续调用size(),这个调用结束后,返回的是一个size_t类型值对象,由auto类型对象sz接收

引用返回左值
调用一个返回引用的函数,在调用处得到左值(左值可以放在赋值号左边用来被赋值)
调用返回其他类型的函数,在调用处得到右值(右值可以放在赋值号右边用来赋值)
可以像使用其他左值那样来使用返回左值(返回引用)的函数调用,特别是能为返回类型是非常量引用的函数结果进行赋值。如下例:
但如果函数的返回值类型是常量引用,就不能给调用结果进行赋值了,这是常量特性所决定的

char &get_val(string &str, string::size_type ix) { //该函数的返回值类型是非常量引用,其返回结果可以在调用处被当作左值
    return str[ix]; //假定索引值ix一定合法
}

const string &shorterStr(const string &s1, const string &s2) { //此函数返回的是常量引用
    return s1.size() <= s2.size() ? s1 : s2; 
}

int main() {
    string s("a value");
    cout << s << endl; //输出:a value
    get_val(s, 0) = 'A'; //get_val的返回结果在此处被当作左值,因为它的返回值类型是非常量引用,可以完成这里的赋值操作,将s[0]的值改为A
    cout << s << endl; //输出:A value
    shoterStr("hi", "bye") = "X"; //❌,返回的是常量引用(也就是常量对象),不能被修改,因此也不能这样作为左值使用
    return 0;
}

该文章会更新,欢迎大家批评指正。

推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容
点击立即学习:C/C++后台高级服务器课程

你可能感兴趣的:(C++编程基础,c++)