结构体作为函数的输入与输出
  本节阅读量: 
  
  考虑由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++和面向对象编程的核心)直接构建在这里介绍的概念之上。很好地理解结构体(特别是数据成员、成员选择和默认成员初始化)将使您更容易过渡到类。
        
        
        