C++ 中的结构体
C++ 结构体用于创建用户自定义数据类型,这些类型可用于存储不同数据类型的数据项集合。
struct 关键字用于定义结构体。结构体中的元素称为其成员,它们可以是任何有效的数据类型。
结构体的应用包括创建数据结构,如链表和树。结构体还可用于在软件中表示现实世界的对象,例如大学管理软件中的学生和教职工。
与 C 语言中的结构体不同,在 C++ 中创建结构体类型的变量时,无需使用 struct 关键字。 在 C++ 中,结构体可以包含方法和构造函数。
1.语法
在使用结构体之前,我们首先需要使用 struct 关键字来定义结构体,具体形式如下:
cpp
struct 结构体名称
{
类型1 成员1;
类型2 成员2;
...
};
示例:
上述过程也称为结构体定义。结构体定义本身不会分配任何内存,也不能直接在程序中使用。我们必须创建该结构体的变量才能使用它。
2.结构体变量
结构体定义后,可以像创建基本数据类型变量一样创建结构体变量。
cpp
struct_name var_name;
其中 struct_name 是结构体的名称,var_name 是变量的名称。
变量也可以在定义结构体的同时声明:
cpp
struct name
{
type1 mem1;
type2 mem2;
...
} var1, var2;
3.初始化结构体成员
结构体成员不能在声明时初始化。例如,以下 C++ 程序编译失败:
cpp
struct Point
{
int x = 0;
int y = 0;
};
结构体成员可以使用花括号 {} 中提供的值进行初始化。例如:
cpp
struct Point
{
int x, y;
};
int main()
{
// 使用花括号初始化结构体的数据成员
Point p1 = {0, 1};
return 0;
}
花括号 {} 中提供的值会按顺序分配给结构体成员。在上面的例子中,0 分配给成员 x,1 分配给成员 y。
从 C++20 开始,我们还可以使用指定初始化器(Designated Initializers)来初始化结构体成员。
4.访问和修改成员
结构体成员使用点运算符(.)访问,也可以使用赋值运算符(=)赋新值。
cpp
var_name.member_name; // 访问成员
var_name.member_name = new_val; // 修改成员
cpp
#include <iostream>
using namespace std;
struct Point
{
int x, y;
};
int main()
{
Point p = {0, 1};
// 访问成员
cout << p.x << " ";
cout << p.y << endl;
// 修改成员
p.x = 99;
// 再次访问成员
cout << p.x << " ";
cout << p.y;
return 0;
}
0 1
99 1
5.结构体中的成员函数
在C语言结构体中,不允许在结构体内部定义函数,但在C++中,我们可以在结构体内部声明函数。它们被称为 结构体_成员函数 ,而变量被称为 结构体_数据成员。与C结构体相比,C++结构体与C++类更加相似。
cpp
#include <iostream>
using namespace std;
struct Point
{
int x, y;
// 成员函数
int sum()
{
return x + y;
}
};
int main()
{
Point s = {0, 1};
// 使用点运算符(.)调用成员函数
cout << s.sum();
return 0;
}
1
C++结构体还支持其他类组件,如构造函数、析构函数、访问说明符等。
cpp
#include <iostream>
using namespace std;
struct Point
{
private:
int x, y;
public:
// 构造函数
Point(int a, int b)
{
x = a;
y = b;
}
// 成员函数
void show()
{
cout << x << " " << y << endl;
}
// 析构函数
~Point()
{
cout << "Destroyed Point Variable" << endl;
}
};
int main()
{
// 使用构造函数创建Point变量
Point s1(1, 1);
Point s2(99, 1001);
s1.show();
s2.show();
return 0;
}
yaml
1 1
99 1001
Destroyed Point Variable
Destroyed Point Variable
6.结构体的大小
结构体的大小由其各个数据成员的大小之和决定,但编译器会添加额外的填充(padding)以确保适当的 内存对齐。
cpp
#include <iostream>
using namespace std;
struct GfG
{
char c; 1字节
int x; 4字节
int y; 4字节
};
int main()
{
// 计算大小
cout << sizeof(GfG);
return 0;
}
12
理想情况下,大小应该是所有数据成员的大小之和,即 sizeof(char) + 2 * sizeof(int) = 1 + 8 = 9 字节。但实际输出的大小却是 12[4+4+4] 字节。这就是由于前面提到的结构体填充造成的。
成员函数不会增加结构体的大小。此外,在 C++ 中,结构体的大小不能为 0。
7.typedef
在 C++ 中,typedef 用于为现有变量创建别名。类似地,对于结构体,typedef 会为结构体的原始名称创建一个别名。
cpp
#include <iostream>
using namespace std;
typedef struct GeeksforGeeks
{
int x, y;
} GfG; // 在此处指定别名
int main()
{
// 使用别名
GfG s = {0, 1};
cout << s.x << " " << s.y << endl;
return 0;
}
0 1
8.嵌套结构体
C++中的嵌套结构体指的是在一个结构体内部定义的另一个结构体。就像结构体成员在结构体内部声明一样,一个结构体也可以作为成员声明在另一个结构体内部。
cpp
#include <iostream>
using namespace std;
// 定义内部结构体
struct inner
{
int a, b;
};
// 定义包含内部结构体的外部结构体
struct outer
{
inner in;
int x, y;
};
int main()
{
outer obj = {{1, 2}, 10, 20};
cout << "Inner: " << obj.in.a << " " << obj.in.b << endl;
cout << "Outer: " << obj.x << " " << obj.y;
return 0;
}
makefile
Inner: 1 2
Outer: 10 20
注意初始化时多添加了一对花括号。这是为了初始化内部结构体。
内部结构体也可以直接定义在外部结构体内部,甚至无需为结构体命名,只需创建一个变量名即可。
cpp
#include <iostream>
using namespace std;
// 定义包含内部结构体的外部结构体
struct outer{
// 嵌套结构体
struct inner{
int a, b;
} in;
int x, y;
};
int main()
{
outer obj = {{1, 2}, 10, 20};
cout << "Inner: " << obj.in.a << " " << obj.in.b << endl;
cout << "Outer: " << obj.x << " " << obj.y;
return 0;
}
makefile
Inner: 1 2
Outer: 10 20
9.结构体指针
在 C++ 中,指向结构体的指针也被称为结构体指针。它是一个指针,保存着结构体存储的内存位置的地址。访问结构体成员的正常方式是先解引用指针,然后使用点运算符,但 C++ 提供了 -> 箭头运算符,可以直接通过指针访问结构体成员。
cpp
#include <iostream>
using namespace std;
struct GfG{
int count;
void showCount(){
cout << count << endl;
}
};
int main(){
GfG gfg = {224};
GfG *sptr = &gfg; // 创建指针
sptr->showCount(); // 使用箭头运算符访问
return 0;
}
224
10.自引用结构体
自引用结构体是指包含指向相同类型指针作为成员的结构体。例如:
cpp
// 自引用结构体
struct GfG {
int val;
// 指向相同类型的指针
GfG *next;
}
这类结构体用于链表、树等数据结构中。
结构体只能包含指向相同类型的指针,而不能包含相同类型的变量。这是因为在结构体完整定义之前无法推导其大小信息。
11.结构体与函数
结构体在函数中的使用方式与其他变量类似。我们可以将结构体传递给函数或从函数返回结构体,就像处理其他变量一样。此外,我们可以按值或按引用传递结构体。然而,推荐的做法是按引用传递结构体,因为复制结构体是一个开销较大的操作。
12.结构体与类
在 C++ 中,结构体的工作方式与类相似,但它们之间存在一些关键差异。重要的区别在于实现细节的处理方式。
默认情况下,结构体不隐藏其实现细节,允许任何使用该结构体的人访问它们。另一方面,类默认会隐藏其实现细节,从而阻止程序员访问它们。