结构体作为函数的输入与输出
本节阅读量:
考虑由3个松散变量表示的员工:
1
2
3
4
5
6
7
8
|
int main()
{
int id { 1 };
int age { 24 };
double wage { 52400.0 };
return 0;
}
|
如果要将此员工传递给函数,必须传递三个变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <iostream>
void printEmployee(int id, int age, double wage)
{
std::cout << "ID: " << id << '\n';
std::cout << "Age: " << age << '\n';
std::cout << "Wage: " << wage << '\n';
}
int main()
{
int id { 1 };
int age { 24 };
double wage { 52400.0 };
printEmployee(id, age, wage);
return 0;
}
|
虽然传递3个单独的员工变量并不是那么糟糕,但考虑需要传递多个员工变量的函数。独立传递每个变量将非常容易出错。此外,如果向员工添加新属性(例如名称),现在必须修改所有函数声明、定义和函数调用,以接受新的参数!
通过引用传递结构体
与单个变量相比,使用结构体的一大优势是,可以将整个结构体传递给函数。结构体通常通过引用传递(通常是常量引用),以避免进行复制。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include <iostream>
struct Employee
{
int id {};
int age {};
double wage {};
};
void printEmployee(const Employee& employee) // 注: 通过引用传递
{
std::cout << "ID: " << employee.id << '\n';
std::cout << "Age: " << employee.age << '\n';
std::cout << "Wage: " << employee.wage << '\n';
}
int main()
{
Employee joe { 14, 32, 24.15 };
Employee frank { 15, 28, 18.27 };
// 打印 Joe 的信息
printEmployee(joe);
std::cout << '\n';
// 打印 Frank 的信息
printEmployee(frank);
return 0;
}
|
在上面的示例中,将整个Employee传递给printEmployere()(一次用于joe,一次为frank)。
上述程序输出:
1
2
3
4
5
6
7
|
ID: 14
Age: 32
Wage: 24.15
ID: 15
Age: 28
Wage: 18.27
|
因为传递的是整个结构体对象(而不是单个成员变量),所以无论有多少个成员变量,都只需要一个参数。而且,如果决定向Employee结构体中添加新成员变量,则不必更改函数声明或函数调用!新成员变量将自动包含在内。
结构体作为返回值
考虑这样的情况,有一个函数需要返回三维空间中的一个点。这样的点有3个属性:x坐标、y坐标和z坐标。但函数只能返回一个值。那么如何将所有3个坐标返回给用户呢?
一种常见的方法是返回结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include <iostream>
struct Point3d
{
double x { 0.0 };
double y { 0.0 };
double z { 0.0 };
};
Point3d getZeroPoint()
{
// 创建一个临时变量并返回
Point3d temp { 0.0, 0.0, 0.0 };
return temp;
}
int main()
{
Point3d zero{ getZeroPoint() };
if (zero.x == 0.0 && zero.y == 0.0 && zero.z == 0.0)
std::cout << "The point is zero\n";
else
std::cout << "The point is not zero\n";
return 0;
}
|
这将打印:
结构体通常按值返回,避免返回悬空引用。
在上面的getZeroPoint() 函数中,创建了一个新的命名对象(temp),以便可以返回它:
1
2
3
4
5
6
|
Point3d getZeroPoint()
{
// 创建一个临时变量并返回
Point3d temp { 0.0, 0.0, 0.0 };
return temp;
}
|
对象(temp)的名称在这里没有任何说明文档的能力。
因此可以通过返回临时(未命名/匿名)对象来稍微改进函数:
1
2
3
4
|
Point3d getZeroPoint()
{
return Point3d { 0.0, 0.0, 0.0 }; // 返回一个未命名的 Point3d
}
|
在这种情况下,将构造临时Point3d,将其复制回调用方,然后在表达式末尾销毁。这里比上面更加简洁(一行对两行,并且不需要了解temp是否被多次使用)。
返回类型推导
在函数具有显式返回类型(例如Point3d)的情况下,甚至可以在return语句中省略该类型:
1
2
3
4
5
6
|
Point3d getZeroPoint()
{
// 因为函数声明中已经指定返回类型
// 因此这里无需再指定
return { 0.0, 0.0, 0.0 }; // 返回一个未命名的 Point3d
}
|
还要注意,由于在这种情况下,如果想要返回一个为零的结构体,可以使用空大括号来返回Point3d:
1
2
3
4
5
|
Point3d getZeroPoint()
{
// 空大括号,来进行值初始化
return {};
}
|
结构体是一个很重要的代码组件
结构体很有用,类(是C++和面向对象编程的核心)直接构建在这里介绍的概念之上。很好地理解结构体(特别是数据成员、成员选择和默认成员初始化)将使您更容易过渡到类。