第七章 函数
code:
/* 第七章 函数 第7章 函数 7.1 函数的定义 7.2 参数传递 7.3 return语句 7.4 函数声明 7.5 局部对象 7.6 内联函数 7.7 类的成员函数 7.8 重载函数 7.9 指向函数的指针 小结 第7章 函数 195 7.1 函数的定义 196 7.1.1 函数返回类型 197 7.1.2 函数形参表 198 7.2 参数传递 199 7.2.1 非引用形参 199 7.2.2 引用形参 201 7.2.3 vector和其他容器类型的形参 206 7.2.4 数组形参 206 7.2.5 传递给函数的数组的处理 209 7.2.6 main:处理命令行选项 210 7.2.7 含有可变形参的函数 211 7.3 return语句 211 7.3.1 没有返回值的函数 212 7.3.2 具有返回值的函数 212 7.3.3 递归 216 7.4 函数声明 217 7.5 局部对象 220 7.5.1 自动对象 220 7.5.2 静态局部对象 220 7.6 内联函数 221 7.7 类的成员函数 222 7.7.1 定义成员函数的函数体 223 7.7.2 在类外定义成员函数 225 7.7.3 编写Sales_item类的构造 函数 225 7.7.4 类代码文件的组织 227 7.8 重载函数 228 7.8.1 重载与作用域 230 7.8.2 函数匹配与实参转换 231 7.8.3 重载确定的三个步骤 232 7.8.4 实参类型转换 234 7.9 指向函数的指针 237 小结 239 术语 240 */ // 7.1 函数的定义 ------------------------------------------------------------------------------------------------ #include <iostream> using namespace std; // return the greatest common divisor,即GCD,最大公约数 int gcd(int v1, int v2) { while(v2) { int temp = v2; v2 = v1 % v2; v1 = temp; } return v1; } int main() { // get values from standard input cout << "Enter two values: \n"; int i, j; cin >> i >> j; // call gcd on arguments i and j // and print their greatest common divisor cout << "gcd: " << gcd(i,j) << endl; return 0; } // 实数为参数 #include <iostream> using namespace std; int gcd(int v1, int v2) { while(v2) { int temp = v2; v2 = v1 % v2; v1 = temp; } return v1; } int main() { double i(3.14),j(6.29); cout << "gcd: " << gcd(i,j) << endl; //合法,可以运行 return 0; } // 7.2 参数传递 ------------------------------------------------------------------------------------------------ // 传值,原值不变 #include <iostream> using namespace std; int gcd(int v1, int v2) { while(v2) { int temp = v2; v2 = v1 % v2; v1 = temp; } return v1; } int main() { int i(8),j(12); cout << "gcd: " << gcd(i,j) << endl; cout << i << ' ' << j << endl; // 不变 return 0; } // 指针为参数 #include <iostream> using namespace std; void reset(int *ip) { *ip=0; ip=0; // 指针为0 } int main() { int i(42); int *p=&i; cout << i << ' ' << p << endl; reset(p); cout << i << ' ' << p << endl; // 指针不变 return 0; } // const 保护指针指向的值 #include <iostream> using namespace std; void reset(const int *ip) // const 是为了保护指针指向的值,而非指针 { //*ip=0; // error 指针指向的值不可以改变 ip=0; // ip可以改变。但因为传值,变也也没啥用 } int main() { int i(42); int *p=&i; cout << i << ' ' << p << endl; reset(p); cout << i << ' ' << p << endl; // 指针不变 return 0; } // const int参数 #include <iostream> using namespace std; int gcd(const int v1, int v2) // const后,v1变成可读不可写了 { int v=v1; // 这样可以解决问题 while(v2) { int temp = v2; v2 = v % v2; v = temp; } return v; } int main() { int i(8),j(12); cout << "gcd: " << gcd(i,j) << endl; cout << i << ' ' << j << endl; // 不变 return 0; } // 无效的交换 #include <iostream> using namespace std; // incorrect version of swap: The arguments are not changed! void swap(int v1, int v2) { int tmp = v2; v2 = v1; // assigns new value to local copy of the argument v1 = tmp; } // local objects v1 and v2 no longer exist int main() { int i = 10; int j = 20; cout << "Before swap():\ti: " << i << "\tj: " << j << endl; swap(i, j); cout << "After swap():\ti: " << i << "\tj: " << j << endl; return 0; } // 引用,相当于传址 #include <iostream> using namespace std; void swap(int &v1, int &v2) // &是引用,不是取地址。相当于pascal中加var,传址 { int tmp = v2; v2 = v1; v1 = tmp; } int main() { int i = 10; int j = 20; cout << "Before swap():\ti: " << i << "\tj: " << j << endl; swap(i, j); cout << "After swap():\ti: " << i << "\tj: " << j << endl; return 0; } // 书中代码补完整 #include <iostream> #include <vector> using namespace std; // returns an iterator that refers to the first occurrence of value // the reference parameter occurs contains a second return value vector < int > ::const_iterator find_val( vector < int > ::const_iterator beg, // first element vector < int > ::const_iterator end, // one past last element int value, // the value we want vector < int > ::size_type &occurs ) // number of times it occurs. notice &&&&&&&&& { // res_iter will hold first occurrence, if any vector < int > ::const_iterator res_iter = end; occurs = 0; // set occurrence count parameter for( ; beg !=end; ++beg) if(*beg == value) { // remember first occurrence of value if(res_iter == end) res_iter = beg; ++occurs; // increment occurrence count } return res_iter; // count returned implicitly in occurs } int main() { vector<int>::size_type st=0; vector<int> v(3,8); vector < int > ::const_iterator it=find_val(v.begin(),v.end(),8,st); cout << it-v.begin() << ' ' << st << endl; it=find_val(v.begin(),v.end(),6,st); cout << it-v.begin() << ' ' << st << endl; return 0; } // 利用 const 引用避免复制 #include <iostream> #include <vector> #include <string> using namespace std; bool isShorter(const string &s1, const string &s2) { return s1.size() < s2.size(); } using namespace std; int main() { string sa,sb; cin>>sa>>sb; cout << isShorter(sa,sb) << endl; return 0; } // error.. #include <iostream> #include <vector> #include <string> using namespace std; // function takes a non-const reference parameter int incr(int &val) // 只能与完全同类型的非 const 对象关联 { 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 return 0; } // 应该将不需要修改的引用形参定义为 const 引用 #include <iostream> #include <vector> #include <string> using namespace std; string::size_type find_char(string const &s, char c) //若无const,无法通过编译 { string::size_type i = 0; while(i != s.size() && s[i] != c) ++i; // not found, look at next character return i; } int main() { if(find_char("Hello World", 'o')) cout << "yes" << endl; return 0; } // int * & ... #include <iostream> #include <vector> #include <string> using namespace std; // swap values of two pointers to int void ptrswap(int * &v1, int * &v2) { int *tmp = v2; //交换两指针 v2 = v1; v1 = tmp; } int main() { int i = 10; int j = 20; int *pi = &i; // pi points to i int *pj = &j; // pj points to j cout << "Before ptrswap():\t*pi: " << *pi << "\t*pj: " << *pj << endl; cout << pi << "\t" << pj << endl; ptrswap(pi, pj); // now pi points to j; pj points to i cout << "After ptrswap():\t*pi: " << *pi << "\t*pj: " << *pj << endl; cout << pi << "\t" << pj << endl; //会发现,地址交换过了 return 0; } /* 通常,函数不应该有 vector 或其他标准库容器类型的形参。调用含有普通的非引用 vector 形参的函数将会复制 vector 的每一个元素。 事实上,C++ 程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器: */ #include <iostream> #include <vector> #include <string> using namespace std; // 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; } int main() { vector<int> v(5,8); print(v.begin(), v.end()); return 0; } /* 数组有两个特殊的性质 一是不能复制数组; 二是使用数组名字时,数组名会自动转化为指向其第一个元素的指针 */ // 三个写法,一样的 #include <iostream> #include <vector> #include <string> using namespace std; void printa( int *a, int n ) { for( int i=0; i<n; ++i ) cout << a[i] << " "; } void printb( int b[], int n ) { for( int i=0; i<n; ++i ) cout << b[i] << " "; } void printc( int c[8], int n ) { for( int i=0; i<n; ++i ) cout << c[i] << " "; } int main() { int ar[8]={8}; printa(ar,8); cout << endl; printb(ar,8); cout << endl; printc(ar,8); cout << endl; return 0; } // 不需要修改数组形参的元素时,函数应该将形参定义为指向 const 对象的指针 #include <iostream> #include <vector> #include <string> using namespace std; void printa( const int *a, int n ) // const { for( int i=0; i<n; ++i ) cout << a[i] << " "; } void printb( const int b[], int n ) { for( int i=0; i<n; ++i ) cout << b[i] << " "; } void printc( const int c[8888], int n ) // 8888 会被忽略 { for( int i=0; i<n; ++i ) cout << c[i] << " "; } int main() { int ar[8]={8}; printa(ar,8); cout << endl; printb(ar,8); cout << endl; printc(ar,8); cout << endl; return 0; } // 引用数组,用本身,不再用指针副本 #include <iostream> #include <vector> #include <string> using namespace std; // 数组元素个数必须完全一样,因为引用的是本身。 void printValues( const int (&a)[10] ) // &a[10]会变成a[10]的引用,因为[]的优先级高 { // 因为不改变数组,加const吧 for(int i = 0; i < 10; ++i) cout << a[i] << " "; } 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; } // 多维数组的传递 #include <iostream> #include <vector> #include <string> using namespace std; /* void printa( int (matrix*)[10], int rowSize) // 编译过不了????????? { cout << "do nothing" << endl; } */ void printb( int matrix[][10], int rowSize) { cout << "do nothing ??? " << endl; } int main() { int ar[10][10]={8}; //printa( ar, 10 ); printb( ar, 10 ); return 0; } #include <iostream> #include <vector> #include <string> using namespace std; 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; } #include <iostream> #include <vector> #include <string> using namespace std; // 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; } // 7.3 return语句 ------------------------------------------------------------------------------------------------ #include <iostream> using namespace std; void swap(int &v1, int &v2) { if(v1==v2) return; // 相等,不用换了 int tmp = v2; v2 = v1; v1 = tmp; } int main() { int i = 10; int j = 20; cout << "Before swap():\ti: " << i << "\tj: " << j << endl; swap(i, j); cout << "After swap():\ti: " << i << "\tj: " << j << endl; return 0; } // 这种做法像没事找抽 #include <iostream> using namespace std; 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 } int main() { int i = 10; int j = 20; cout << "Before swap():\ti: " << i << "\tj: " << j << endl; swap(i, j); cout << "After swap():\ti: " << i << "\tj: " << j << endl; return 0; } // ************如果程序控制执行到主函数 main 的最后一个语句都还没有返回,那么编译器会隐式地插入返回 0 的语句。*********** #include <iostream> #include <string> using namespace std; const string &shorter(const string &s1, const string &s2) { return s1.size() < s2.size() ? s1:s2; } using namespace std; int main() { string sa,sb; cin>>sa>>sb; cout << shorter(sa,sb) << endl; } // **千万不要返回局部对象的引用** #include <iostream> #include <string> using namespace std; const string &shorter(const string &s1, const string &s2) { string s3(s1),s4(s2); //确保返回引用安全的一个好方法是:请自问,这个引用指向哪个在此之前存在的对象? return s1.size() < s2.size() ? s3:s4; // runtime error! 因为返回的是引用,引用即本身。如果返回s3,而s3是局部变量,释放了! } using namespace std; int main() { string sa,sb; cin>>sa>>sb; cout << shorter(sa,sb) << endl; } // 函数可以作为左值?确实新颖 #include <iostream> #include <string> using namespace std; 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; } // 递归求阶乘 #include <iostream> #include <string> using namespace std; int factorial(int val) { if(val>1) return factorial(val-1)*val; return 1; } int main() { cout << factorial(5) << endl; } // 递归之辗转相除法,求GCD #include <iostream> #include <string> using namespace std; // recursive version greatest common divisor program int rgcd(int v1, int v2) { if(v2 != 0) // we're done once v2 gets to zero return rgcd(v2, v1 % v2); // recurse, reducing v2 on each call return v1; } int main() { cout << rgcd(15,123) << endl; } // 输出中间过程 #include <iostream> #include <string> using namespace std; int rgcd(int v1, int v2) { cout << v1 << "\t" << v2 << endl; // if(v2 != 0) return rgcd(v2, v1 % v2); return v1; } int main() { cout << rgcd(15,123) << endl; } // 7.4 函数声明 ------------------------------------------------------------------------------------------------ /* 如果有一个形参具有默认实参,那么,它后面所有的形参都必须有默认实参。 ——主要是因为调用的需要。参数可以写前面的n个。。 设计带有默认实参的函数,其中部分工作就是排列形参,使最少使用默认实参的形参排在最前,最可能使用默认实参的形参排在最后。 既可以在函数声明也可以在函数定义中指定默认实参。 通常,应在函数声明中指定默认实参,并将该声明放在合适的头文件中。 */ #include <iostream> #include <string> using namespace std; int myplus(int a=1, int b=2, int c=3, int d=4) { return(a+b+c+d); } int main() { cout << myplus() << endl; cout << myplus(2) << endl; cout << myplus(2,3) << endl; cout << myplus(2,3,4) << endl; cout << myplus(2,3,4,5) << endl; } // 7.5 局部对象 ------------------------------------------------------------------------------------------------ #include <iostream> #include <string> using namespace std; int sum(0); // 用全局变量也可以统计 size_t count_calls() { static size_t ctr = 0; // value will persist across calls ++sum; return ++ctr; } int main() { for(size_t i = 0; i != 10; ++i) cout << count_calls() << endl; cout << endl << sum << endl; } // 7.6 内联函数 ------------------------------------------------------------------------------------------------ /* 一、节省调用开销 二、不支持递归,代码短小 三、内联函数应该在头文件中定义,这一点不同于其他函数。 */ #include <iostream> #include <string> using namespace std; //inline inline const string &shorter(const string &s1, const string &s2) { return s1.size() < s2.size() ? s1:s2; } using namespace std; int main() { string sa,sb; cin>>sa>>sb; cout << shorter(sa,sb) << endl; } // 7.7 类的成员函数 ------------------------------------------------------------------------------------------------ // 这节无可执行代码。this 解释得比较清楚 // 7.8 重载函数 --------------------------------------------------------------------------------------------------- // 7.9 指向函数的指针 ------------------------------------------------------------------------------------------------ #include <iostream> #include <string> using namespace std; bool lengthCompare (const string &s1, const string &s2) { return s1.size() < s2.size(); } int main() { typedef bool(*cmpFcn)(const string &, 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 bool b; b=(*pf)("hi", "bye"); // equivalent call: pf1 explicitly dereferenced cout << b << endl; string sa("abcd"),sb("ab"); cout << (*pf1)(sa,sb) << endl; cout << (*pf2)(sa,sb) << endl; }