①函数不能返回另一个函数或者内置数组类型,但可以返回指向函数的指针,或指向数组元素的指针的指针
②函数的参数传递:
1.传值得局限性:
当需要在函数中修改实参的值时。
当需要以大型对象作为实参传递时。对实际的应用而言,复制对象所付出的时间和存储空间代价往往过在。
当没有办法实现对象的复制时。
2.引用形参:利用const引用避免复制
// compare the length of two strings
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
3.传递指向指针的引用
// swap values of two pointers to int
void ptrswap(int *&v1, int *&v2)
{
int *tmp = v2;
v2 = v1;
v1 = tmp;
}
定义应从右至左理解:v1 是一个引用,与指向 int 型对象的指针相关联。
4.Vector和其他容器类型的形参:从避免复制vector 的角度出发,应考虑将形参声明为引用类型。事实上,C++ 程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器:
// pass iterators to the first and one past the last element to print
void print(vector<int>::const_iterator beg,
vector<int>::const_iterator end)
{
while (beg != end) {
cout << *beg++;
if (beg != end) cout << " "; // no space after last element
}
cout << endl;
}
5.数组的形参:
1.以下是三种等价的定义方式:
// three equivalent definitions of printValues
void printValues(int*) { /* ... */ }
void printValues(int[]) { /* ... */ }
void printValues(int[10]) { /* ... */ }
2.编译器忽略为任何数组形参指定的长度
3.通过引用传递数组,如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型的一部分。编译器检查数组的实参的大小与形参的大小是否匹配。
// ok: parameter is a reference to an array; size of array is fixed
void printValues(int (&arr)[10]) { /* ... */ }
int main()
{
int i = 0, j[2] = {0, 1};
int k[10] = {0,1,2,3,4,5,6,7,8,9};
printValues(&i); // error: argument is not an array of 10 ints
printValues(j); // error: argument is not an array of 10 ints
printValues(k); // ok: argument is an array of 10 ints
return 0;
}
4.多维数组的传递:
// first parameter is an array whose elements are arrays of 10 ints
void printValues(int (matrix*)[10], int rowSize);
我们也可以用数组语法定义多维数组。与一维数组一样,编译器忽略第一维的长度,所以最好不要把它包括在形参表内:
// first parameter is an array whose elements are arrays of 10 ints
void printValues(int matrix[][10], int rowSize);
5.传递给函数的数组的处理:
使用标准库规范
void printValues(const int *beg, const int *end)
{
while (beg != end) {
cout << *beg++ << endl;
}
}
int main()
{
int j[2] = {0, 1};
// ok: j is converted to pointer to 0th element in j
// j + 2 refers one past the end of j
printValues(j, j + 2);
return 0;
}
显示的传入数组的长度:
// const int ia[] is equivalent to const int* ia
// size is passed explicitly and used to control access to elements of ia
void printValues(const int ia[], size_t size)
{
for (size_t i = 0; i != size; ++i) {
cout << ia[i] << endl;
}
}
int main()
{
int j[] = { 0, 1 }; // int array of size 2
printValues(j, sizeof(j)/sizeof(*j));
return 0;
}
6.main: 处理命令行选项
int main(int argc, char *argv[]) { ... }
第二个形参 argv 是一个 C 风格字符串数组。第一个形参argc 则用于传递该数组中字符串的个数。
③函数的返回值:
1.void表示没有返回值,此时不用在函数内部添加return,或者添加return;。
2.返回非引用的类型:函数的返回值用于初始化在调用函数处创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。当函数返回非引用类型时,其返回值既可以是局部对象,也可以是求解表达式的结果。
// 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;
}
3.返回引用的类型:当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。千万注意:不能返回局部变量的引用。
// find longer of two strings
const string &shorterString(const string &s1, const string &s2)
{
return s1.size() < s2.size() ? s1 : s2;
}
形参和返回类型都是指向 const string 对象的引用,调用函数和返回结果时,都没有复制这些 string 对象。
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(...
5. 千万不要返回指向局部对象的指针: 一旦函数结束,局部对象被释放,返回的指针就变成了指向不再存在的对象的悬垂指针。
④函数的声明:
1.函数的声明也可以和函数的定义分离;一个函数只能定义一次,但是可声明多次。
2.函数也应当在头文件中声明,并在源文件中定义。
⑤局部对象:
1.局部变量的生命期局限于所在函数的每次执行期间。只有当定义它的函数被调用时才存在的对象称为自动对象。自动对象在每次调用函数时创建和撤销。
2.形参也是自动对象。形参所占用的存储空间在调用函数时创建,而在函数结束时撤销。
3.静态局部对象(Static Local Objects):当定义静态局部对象的函数结束时,静态局部对象不会撤销。
size_t count_calls()
{
static size_t ctr = 0; // value will persist across calls
return ++ctr;
}
int main()
{
for (size_t i = 0; i != 10; ++i)
cout << count_calls() << endl;
return 0;
}
inline const string &
shorterString(const string &s1, const string &s2)
{
return s1.size() < s2.size() ? s1 : s2;
}
头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。
⑦类的成员函数:
bool same_isbn(const Sales_item &rhs) const
{ return isbn == rhs.isbn; }
1.const成员函数不能修改调用该函数的对象。因此函数
same_isbn 只能读取而不能修改调用它们的对象的数据成员。
2.构造函数和初始化列表:
Sales_item(): units_sold(0), revenue(0.0) { }
⑧重载函数:函数名相同,函数的参数不一样的才能进行重载
⑨指向函数的指针:
typedef bool (*cmpFcn)(const string &, const string &);
该指针类型为“指向返回
bool 类型并带有两个
const string 引用形参的函数的指针”。
cmpFcn pf1 = 0; // ok: unbound pointer to function
cmpFcn pf2 = lengthCompare; // ok: pointer type matches function's type
pf1 = lengthCompare; // ok: pointer type matches function's type
pf2 = pf1; // ok: pointer types match
通过指针调用函数
cmpFcn pf = lengthCompare;
lengthCompare("hi", "bye"); // direct call
pf("hi", "bye"); // equivalent call: pf1 implicitly dereferenced
(*pf)("hi", "bye"); // equivalent call: pf1 explicitly dereferenced
函数指针形参
void useBigger(const string &, const string &,
bool(const string &, const string &));
// equivalent declaration: explicitly define the parameter as a pointer to function
void useBigger(const string &, const string &,
bool (*)(const string &, const string &));