函数不能返回另一个函数或者内置数组类型,但可以返回指向函数的指针,或指向数组元素的指针的指针:
// ok: pointer to first element of the array
int *foo_bar() { /* ... */ }
形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值,如果形参为引用类型(第 2.5 节),则它只是实参的别名。
void reset(int *ip)
{
*ip = 0; // changes the value of the object to which ip points
ip = 0; // changes only the local value of ip; the argument is unchanged
}
void use_ptr(const int *p)
{
// use_ptr may read but not write to *p
}
指针形参是指向 const 类型还是非 const 类型,将影响函数调用所使用的实参。我们既可以用int* 也可以用
const int* 类型的实参调用 use_ptr 函数;但仅能将 int* 类型的实参传递给reset 函数。这个差别来源于指针的初始化规则(第 4.2.5 节)。可以将指向const 对象的指针初始化为指向非
const 对象,但不可以让指向非 const 对象的指针向 const 对象。
// function takes a non-const reference parameter
int incr(int &val)
{
return ++val;
}
int main()
{
short v1 = 0;
const int v2 = 42;
int v3 = incr(v1); // error: v1 is not an int
v3 = incr(v2); // error: v2 is const
v3 = incr(0); // error: literals are not lvalues
v3 = incr(v1 + v2); // error: addition doesn't yield an lvalue
int v4 = incr(v3); // ok: v3 is a non const object type int
}
问题的关键是非 const 引用形参(第 2.5 节)只能与完全同类型的非const 对象关联。
string &s="Hello World";//error
int &r=12;//error
const string &s="Hello World";ok
const int &r=12;ok
string::size_type find_char(string &s, char c)
{
string::size_type i = 0;
while (i != s.size() && s[i] != c)
++i; // not found, look at next character
return i;
}
这个函数将其 string 类型的实参当作普通(非 const)的引用,尽管函数并没有修改这个形参的值。这样的定义带来的问题是不能通过字符串字面值来调用这个函数:
if (find_char("Hello World", 'o')) // ...
bool is_sentence (const string &s)
{
// if there's a period and it's the last character in s
// then s is a sentence
return (find_char(s, '.') == s.size() - 1);
}
如上代码,函数 is_sentence 中 find_char 的调用是一个编译错误。传递进is_sentence 的形参是指向
const string 对象的引用,不能将这种类型的参数传递给 find_char,因为后者期待得到一个指向非const string 对象的引用。
应该将不需要修改的引用形参定义为 const 引用。普通的非 const 引用形参在使用时不太灵活。这样的形参既不能用const 对象初始化,也不能用字面值或产生右值的表达式实参初始化。
数组有两个特殊的性质,影响我们定义和使用作用在数组上的函数:一是不能复制数组(第 4.1.1 节);二是使用数组名字时,数组名会自动转化为指向其第一个元素的指针(第 4.2.4 节)。因为数组不能复制,所以无法编写使用数组类型形参的函数。因为数组会被自动转化为指针,所以处理数组的函数通常通过操纵指向数组指向数组中的元素的指针来处理数组。
// three equivalent definitions of printValues
void printValues(int*) { /* ... */ }
void printValues(int[]) { /* ... */ }
void printValues(int[10]) { /* ... */ }
虽然不能直接传递数组,但是函数的形参可以写成数组的形式。
不需要修改数组形参的元素时,函数应该将形参定义为指向 const 对象的指针:
|
// f won't change the elements in the array
void f(const int*) { /* ... */ }
千万不能返回局部变量的引用。
// 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 占用的储存空间被释放,函数返回值指向了对于这个程序来说不再有效的内存空间。
// 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 对象。
和返回局部对象的引用一样,返回指向局部对象的指针也是错误的。一旦函数结束,局部对象被释放,返回的指针就变成了指向不再存在的对象的悬垂指针
默认实参是通过给形参表中的形参提供明确的初始值来指定的。程序员可为一个或多个形参定义默认值。但是,如果有一个形参具有默认实参,那么,它后面所有的形参都必须有默认实参。
string screenInit(string::size_type height = 24,
string::size_type width = 80,
char background = ' ' );
string screen;
screen = screenInit(); // equivalent to screenInit (24,80,' ')
screen = screenInit(66); // equivalent to screenInit (66,80,' ')
screen = screenInit(66, 256); // screenInit(66,256,' ')
screen = screenInit(66, 256, '#');
函数调用的实参按位置解析,默认实参只能用来替换函数调用缺少的尾部实参。例如,如果要给
background 提供实参,那么也必须给 height 和 width 提供实参:
screen = screenInit(, , '?'); // error, can omit only trailing arguments
screen = screenInit( '?'); // calls screenInit('?',80,' ')
内联函数应该在头文件中定义,这一点不同于其他函数。
|
inline 函数的定义对编译器而言必须是可见的,以便编译器能够在调用点内联展开该函数的代码。此时,仅有函数原型是不够的。
编译器隐式地将在类内定义的成员函数当作内联函数
分享到:
相关推荐
本课程是C++ Primer初级教程,课程内容是学习C++语言基础知识,对应着教材的第1章到第8章。 第1章 快速入门 1.1 编写简单的C++程序 1.2 初窥输入/输出 1.2.1 标准输入与输出对象 1.2.2 一个使用IO库的程序 ...
C++ Primer习题集(第五版) , 带目录完整版。 --------------------------------------------------------------------------- 目录 第1章............................................................ 1 练习1.1 ...
【原书名】 C++ Primer (4th Edition) 【原出版社】 Addison Wesley/Pearson 【作者】 (美)Stanley B.Lippman,Josée LaJoie,Barbara E.Moo 【译者】 李师贤 蒋爱军 梅晓勇 林瑛 【丛书名】 图灵计算机科学丛书 ...
第3章 标准库 string 类型 (1) 20.第3章 标准库 string 类型 (2) 21.第3章重点习题解答 22.第3章标准库string类型(3) 23.第3章标准库vector类型 24.第3章重点习题解答 25.第3章迭代器简介 26.二进制和...
28.15章 派生类的构造函数和析构函数 29.15章 转换与继承 30.15章 友元与继承 31.15章 静态成员与继承 32.15章 纯虚函数与抽象类 33.16章 模板与泛型编程 34.16章 类模板 - 顺序队列 35.16章 类模板 ...
C++ Primer中文版(第5版)[203M]分3个压缩包 本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数...
C++ primer之泛型函数
C++ Primer结合了Stanley Lippman的实践经验和Josée Lajoie对于ANSI/ISO标准C++的深入理解,此第三版被重新改写,以便更加精确地讲述标准C++的特性和用法。对于C++初学者特别有价值的是一些来自真实世界中的程序...
C++primer 课后题答案 目录 第一章 快速入门 2 第二章 变量和基本类型 7 第三章 标准库类型 13 第四章 数组和指针 21 第五章 表达式 31 第六章 语句 37 第七章 函数 37 第八章 标准IO库 37 第九章 顺序容器 43 第十...
C++Primer中文版_第4版__函数_习题解答_文字分享.pdf
第八章函数探幽 内联函数 默认参数 函数重载 函数模板
C++ Primer Plus学习(七),分为下面几个部分: 操作符重载 友元函数 类的继承 访问控制protected
继承呼唤多态、虚函数、纯虚函数与抽象类、静态联编、动态联编
C++ primer plus学习笔记之三,分为一下几个部分: 函数参数:介绍了函数的生命规则以及定义 数组函数:数组作为变量时的使用方法 指针和const:灵活运用指针和const 函数和二维数组:二维数组作为变量时声明以及定义...
C++由美国AT&T贝尔实验室的本贾尼·斯特劳斯特卢普博士在20世纪80年代初期...国际标准化组织于2011年9月1日出版发布ISO/IEC 14882:2011,名称是:Information technology -- Programming languages -- C++ Edition: 3
C++ Primer中文版(第5版)[203M]分3个压缩包 本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数...
虽然本书书名C++ Primer 的中文含义是C++初级读本但是它绝对不是一本很轻 松的入门教材特别是关于名字空间函数重载解析过程模板机制和泛型算法generic algorithms 等内容并不是一个C++初学者能够很快掌握的如果你...
C++11,使用委派构造函数,并且快速初始化变量,default关键字重声明默认构造函数,回复pod状态。分析与推荐用法。
~\n-----------------------\n 作为Windows开发人员的必备参考,《Windows核心编程》是为打算理解Windows的C和C++程序员精心设计的。第5版全面覆盖 Windows XP,WindowsVista和WindowsServer2008中的170个新增函数和...