# C++ Primer Plus 第6版 读书笔记(8)第 8章 函数探幽（二）

#### 使用传值和引用参数的示例代码

/ cubes.cpp -- regular and reference arguments
#include <iostream>
double cube(double a);
double refcube(double &ra);
int main ()
{
using namespace std;
double x = 3.0;
cout << cube(x);
cout << " = cube of " << x << endl;
cout << refcube(x);
cout << " = cube of " << x << endl;
// cin.get();
return 0;
}
double cube(double a)
{
a *= a * a;
return a;
}
double refcube(double &ra)
{
ra *= ra * ra;
return ra;
}

#include <iostream>
double cube(double a);
double refcube(double &ra);
int main()
{
using namespace std;
double x = 3.0;
cout << cube(x);
cout << " = cube of " << x << endl;
cout << refcube(x);
cout << " = cube of " << x << endl;
return 0;
}
double cube(double a)
{
a *= a * a;
return a;
}
double refcube(double &ra)
{
ra *= ra * ra;
return ra;
}

cube函数使用传值方式计算a的立方。在函数内部，先将a自乘两次，然后将结果返回。

refcube函数使用引用参数计算ra的立方。在函数内部，同样将ra自乘两次，然后将结果返回。由于使用引用参数，函数修改的是原始变量x的值。

#### 将引用用于结构

//strc_ref.cpp -- using structure references
#include <iostream>
#include <string>
struct free_throws
{
std::string name;
int attempts;
float percent;
};
void display(const free_throws & ft);
void set_pc(free_throws & ft);
free_throws & accumulate(free_throws &target, const free_throws &source);
int main()
{
free_throws one = {"Ifelsa Branch", 13, 14};
free_throws two = {"Andor Knott", 10, 16};
free_throws three = {"Minnie Max", 7, 9};
free_throws four = {"Whily Looper", 5, 9};
free_throws five = {"Long Long", 6, 14};
free_throws team = {"Throwgoods", 0, 0};
free_throws dup;
set_pc(one);
display(one);
accumulate(team, one);
display(team);
// use return value as argument
display(accumulate(team, two));
accumulate(accumulate(team, three), four);
display(team);
// use return value in assignment
dup = accumulate(team,five);
std::cout << "Displaying team:\n";
display(team);
std::cout << "Displaying dup after assignment:\n";
display(dup);
set_pc(four);
accumulate(dup,five) = four;
std::cout << "Displaying dup after ill-advised assignment:\n";
display(dup);
// std::cin.get();
return 0;
}
void display(const free_throws & ft)
{
using std::cout;
cout << "Name: " << ft.name << '\n';
cout << "Attempts: " << ft.attempts << '\t';
cout << "Percent: " << ft.percent << '\n';
}
void set_pc(free_throws & ft)
{
if (ft.attempts != 0)
else
ft.percent = 0;
}
free_throws & accumulate(free_throws & target, const free_throws & source)
{
target.attempts += source.attempts;
set_pc(target);
return target;
}

• display函数用于显示一个free_throws对象的内容。它接受一个常量引用参数ft，以避免对原始对象进行修改。在函数内部，使用cout对象输出对象的姓名、投中次数、尝试次数和命中率。
• set_pc函数用于计算和设置投篮命中率。它接受一个非常量引用参数ft，因为它需要修改原始对象的成员变量。在函数内部，通过判断尝试次数是否为0，计算出命中率，并将其赋值给对象的命中率成员变量。
• accumulate函数用于累加两个free_throws对象的数据，并返回一个free_throws引用。它接受一个非常量引用参数target作为目标对象，一个常量引用参数source作为源对象。在函数内部，将目标对象的投中次数和尝试次数分别加上源对象的对应值，并调用set_pc函数更新目标对象的命中率。最后，返回目标对象的引用。

main函数中，首先创建了一些free_throws对象，分别赋值给不同的变量（one、two、three、four、five和team）。这些对象表示了不同篮球队员的投篮数据和一个整个团队的总数据。

### 函数重载

1. 函数名称必须相同，但是参数列表必须不同。
2. 参数列表可以有不同的参数类型、参数顺序或参数数量。
3. 返回类型可以相同也可以不同。
4. 函数重载仅通过函数的名称和参数列表进行区分，与返回类型无关。

#include <iostream>
int add(int a, int b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
float add(float a, float b) {
return a + b;
}
int main() {
int result2 = add(2, 3, 4);
std::cout << result1 << std::endl;  // 输出：5
std::cout << result2 << std::endl;  // 输出：9
std::cout << result3 << std::endl;  // 输出：6.2
return 0;
}

main函数中，通过根据需要选择调用不同版本的add函数，实现了整数相加和浮点数相加的功能，并打印出结果。

### 函数模版

template <typename T>
void functionName(T parameter) {
// 函数体
}

#include <iostream>
// 函数模板，用于交换两个值
template <typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 2;
float c = 1.5f, d = 2.7f;
std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;
swapValues(a, b);
std::cout << "After swap: a = " << a << ", b = " << b << std::endl;
std::cout << "Before swap: c = " << c << ", d = " << d << std::endl;
swapValues(c, d);
std::cout << "After swap: c = " << c << ", d = " << d << std::endl;
return 0;
}

/ funtemp.cpp -- using a function template
#include <iostream>
// function template prototype
template <typename T>  // or class T
void Swap(T &a, T &b);
int main()
{
using namespace std;
int i = 10;
int j = 20;
cout << "i, j = " << i << ", " << j << ".\n";
cout << "Using compiler-generated int swapper:\n";
Swap(i,j);  // generates void Swap(int &, int &)
cout << "Now i, j = " << i << ", " << j << ".\n";
double x = 24.5;
double y = 81.7;
cout << "x, y = " << x << ", " << y << ".\n";
cout << "Using compiler-generated double swapper:\n";
Swap(x,y);  // generates void Swap(double &, double &)
cout << "Now x, y = " << x << ", " << y << ".\n";
// cin.get();
return 0;
}
// function template definition
template <typename T>  // or class T
void Swap(T &a, T &b)
{
T temp;   // temp a variable of type T
temp = a;
a = b;
b = temp;
}

// twotemps.cpp -- using overloaded template functions
#include <iostream>
template <typename T>     // original template
void Swap(T &a, T &b);
template <typename T>     // new template
void Swap(T *a, T *b, int n);
void Show(int a[]);
const int Lim = 8;
int main()
{
using namespace std;
int i = 10, j = 20;
cout << "i, j = " << i << ", " << j << ".\n";
cout << "Using compiler-generated int swapper:\n";
Swap(i,j);              // matches original template
cout << "Now i, j = " << i << ", " << j << ".\n";
int d1[Lim] = {0,7,0,4,1,7,7,6};
int d2[Lim] = {0,7,2,0,1,9,6,9};
cout << "Original arrays:\n";
Show(d1);
Show(d2);
Swap(d1,d2,Lim);        // matches new template
cout << "Swapped arrays:\n";
Show(d1);
Show(d2);
// cin.get();
return 0;
}
template <typename T>
void Swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
template <typename T>
void Swap(T a[], T b[], int n)
{
T temp;
for (int i = 0; i < n; i++)
{
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}
void Show(int a[])
{
using namespace std;
cout << a[0] << a[1] << "/";
cout << a[2] << a[3] << "/";
for (int i = 4; i < Lim; i++)
cout << a[i];
cout << endl;
}

main函数中，首先声明并初始化了两个int类型的变量ij，并输出它们的初始值。然后调用了Swap(i,j)来交换ij的值，因为ij的类型为int，所以编译器会根据Swap模板函数的定义，生成一个专门针对int类型的具体函数。最后，再次输出ij的值，可以看到它们已经被成功交换。

// twoswap.cpp -- specialization overrides a template
#include <iostream>
template <typename T>
void Swap(T &a, T &b);
struct job
{
char name[40];
double salary;
int floor;
};
// explicit specialization
template <> void Swap<job>(job &j1, job &j2);
void Show(job &j);
int main()
{
using namespace std;
cout.precision(2);
cout.setf(ios::fixed, ios::floatfield);
int i = 10, j = 20;
cout << "i, j = " << i << ", " << j << ".\n";
cout << "Using compiler-generated int swapper:\n";
Swap(i,j);    // generates void Swap(int &, int &)
cout << "Now i, j = " << i << ", " << j << ".\n";
job sue = {"Susan Yaffee", 73000.60, 7};
job sidney = {"Sidney Taffee", 78060.72, 9};
cout << "Before job swapping:\n";
Show(sue);
Show(sidney);
Swap(sue, sidney); // uses void Swap(job &, job &)
cout << "After job swapping:\n";
Show(sue);
Show(sidney);
// cin.get();
return 0;
}
template <typename T>
void Swap(T &a, T &b)    // general version
{
T temp;
temp = a;
a = b;
b = temp;
}
// swaps just the salary and floor fields of a job structure
template <> void Swap<job>(job &j1, job &j2)  // specialization
{
double t1;
int t2;
t1 = j1.salary;
j1.salary = j2.salary;
j2.salary = t1;
t2 = j1.floor;
j1.floor = j2.floor;
j2.floor = t2;
}
void Show(job &j)
{
using namespace std;
cout << j.name << ": \$" << j.salary
<< " on floor " << j.floor << endl;
}

main函数中，首先声明并初始化了两个int类型的变量ij，并输出它们的初始值。然后调用了Swap(i, j)来交换ij的值，因为ij的类型为int，所以会选择调用通用版本的Swap模板函数。最后，再次输出ij的值，可以看到它们已经被成功交换。

### 8.6 总结：

C++ 扩展了 C 语言的函数功能，其中包括引入内联函数和引用变量等特性。内联函数可以通过在函数定义前加上 inline 关键字，并在首次调用前提供函数定义来实现。引用变量允许为变量创建别名，主要用于处理结构和类对象的函数参数。需要注意的是，基类引用可以指向派生类对象。

C++ 还支持函数参数默认值的定义，当函数调用省略了某些参数时，程序将使用默认值；当函数调用提供了参数值时，程序将使用提供的值。定义默认参数时需要按照从右到左的顺序提供。

### 8.8 编程练习

1．编写通常接受一个参数（字符串的地址），并打印该字符串的函数。然而，如果提供了第二个参数

（int 类型），且该参数不为 0，则该函数打印字符串的次数将为该函数被调用的次数（注意，字符串的打印次数不等于第二个参数的值，而等于函数被调用的次数）。是的，这是一个非常可笑的函数，但它让您能够使用本章介绍的一些技术。在一个简单的程序中使用该函数，以演示该函数是如何工作的。

2．CandyBar 结构包含 3 个成员。第一个成员存储 candy bar 的品牌名称；第二个成员存储 candy bar的重量（可能有小数）；第三个成员存储 candy bar 的热量（整数）。请编写一个程序，它使用一个这样的函数，即将 CandyBar 的引用、char 指针、double 和 int 作为参数，并用最后 3 个值设置相应的结构成员。最后 3 个参数的默认值分别为“Millennium Munch”、2.85 和 350。另外，该程序还包含一个以 CandyBar 的引用为参数，并显示结构内容的函数。请尽可能使用 const。

3．编写一个函数，它接受一个指向 string 对象的引用作为参数，并将该 string 对象的内容转换为大写， 为此可使用表 6.4 描述的函数 toupper( )。然后编写一个程序，它通过使用一个循环让您能够用不同的输入来测试这个函数，该程序的运行情况如下：

8.8 编程练习：

1. 打印字符串函数
#include <iostream>
#include <string>
void printString(const std::string& str, int n = 1) {
for (int i = 0; i < n; i++) {
std::cout << str << std::endl;
}
}
int main() {
std::string str = "Hello, world!";
printString(str); // 调用一次，打印一次字符串
printString(str, 3); // 调用三次，打印三次字符串
return 0;
}
1. CandyBar 结构和函数
#include <iostream>
#include <string>
struct CandyBar {
std::string brand;
double weight;
int calories;
};
void setCandyBar(CandyBar& candy, const char* brand = "Millennium Munch", double weight = 2.85, int calories = 350) {
candy.brand = brand;
candy.weight = weight;
candy.calories = calories;
}
void showCandyBar(const CandyBar& candy) {
std::cout << "Brand: " << candy.brand << std::endl;
std::cout << "Weight: " << candy.weight << std::endl;
std::cout << "Calories: " << candy.calories << std::endl;
}
int main() {
CandyBar candy;
setCandyBar(candy); // 使用默认参数设置结构成员
showCandyBar(candy); // 显示结构内容
return 0;
}
1. 字符串转大写函数
#include <iostream>
#include <string>
void toUpper(std::string& str) {
for (int i = 0; i < str.length(); i++) {
str[i] = toupper(str[i]);
}
}
int main() {
std::string str;
while (true) {
std::cout << "Please enter a string (q to quit): ";
std::getline(std::cin, str);
if (str == "q") {
break;
}
toUpper(str);
std::cout << "Uppercase: " << str << std::endl;
}
return 0;
}

|
4天前
|
C++
C++静态成员变量及函数
C++静态成员变量及函数
10 0
|
1月前
|
Java 编译器 Linux

95 0
|
1月前
|

【C++入门到精通】C++入门 —— 内存管理（new函数的讲解）

73 0
|
25天前
|

【编码狂想】深度探索C++编程之旅：“数组、字符串、函数与KMP算法解密“
【编码狂想】深度探索C++编程之旅：“数组、字符串、函数与KMP算法解密“
64 0
|
1天前
|
C++
C++模板与STL【函数对象】
C++模板与STL【函数对象】
|
1天前
|

|
1天前
|
C++
C++核心编程三：函数提高（持续更新）
C++核心编程三：函数提高（持续更新）
|
4天前
|
C++
C++函数与值传递
C++函数与值传递
6 0
|
6天前
|

C++：类的默认成员函数
C++：类的默认成员函数
26 0
|
8天前
|

C++ 新特性----＞函数返回类型后置
C++ 新特性----＞函数返回类型后置
8 0

• 云迁移中心

更多

更多