C++ 结构体详解
1. 结构体的概念
在C++中,结构体(struct
) 是一种用户自定义的数据类型,可以将不同类型的变量组合在一起。每个变量叫做结构体的成员,可以是不同数据类型的组合。结构体允许你将多个数据项作为一个单元进行处理,方便存储和操作。
结构体的定义是为了使数据更加有组织,尤其是在需要同时处理多个相关数据时。比如,我们可以用结构体来表示一个学生,学生包含姓名、年龄、成绩等信息。结构体使得管理这些信息更加清晰。
2. 结构体的定义与声明
结构体的定义可以通过struct
关键字来完成,格式如下:
struct 结构体名 {
数据类型 成员名1;
数据类型 成员名2;
数据类型 成员名3;
// ...
};
示例:定义一个简单的结构体
#include <iostream>
using namespace std;
// 定义一个表示学生的结构体
struct Student {
string name; // 姓名
int age; // 年龄
float grade; // 成绩
};
int main() {
// 创建一个Student类型的变量
Student student1;
// 为结构体成员赋值
student1.name = "Tom";
student1.age = 20;
student1.grade = 85.5;
// 输出结构体成员
cout << "Name: " << student1.name << endl;
cout << "Age: " << student1.age << endl;
cout << "Grade: " << student1.grade << endl;
return 0;
}
解释:
-
定义结构体:我们用
struct Student
定义了一个结构体类型Student
,其中包含三个成员:name
(字符串类型)、age
(整数类型)和grade
(浮点数类型)。 -
创建结构体变量:在
main
函数中,我们通过Student student1
声明了一个Student
类型的结构体变量。 -
访问成员:使用
.
操作符来访问和修改结构体变量的成员。
输出:
Name: Tom
Age: 20
Grade: 85.5
3. 结构体初始化
3.1 初始化结构体变量
C++允许在声明结构体变量时直接进行初始化,这样可以在创建结构体实例时就赋予它初始值。
#include <iostream>
using namespace std;
// 定义一个结构体
struct Point {
int x;
int y;
};
int main() {
// 通过初始化列表直接初始化结构体变量
Point p1 = {10, 20};
cout << "x: " << p1.x << ", y: " << p1.y << endl;
return 0;
}
3.2 使用指定初始化
在C++11及以后的版本中,可以使用指定初始化来清晰地初始化结构体成员。
#include <iostream>
using namespace std;
// 定义一个结构体
struct Point {
int x;
int y;
};
int main() {
// 使用指定初始化
Point p1 = {.x = 10, .y = 20};
cout << "x: " << p1.x << ", y: " << p1.y << endl;
return 0;
}
3.3 默认初始化
如果在定义结构体变量时没有提供初始化值,结构体成员将会被默认初始化:
-
如果结构体成员是基本数据类型(如
int
、float
等),则它们的值是未定义的,可能包含垃圾值。 -
如果结构体成员是类类型(如
std::string
),则会调用其默认构造函数进行初始化。
示例:未初始化的结构体
#include <iostream>
using namespace std;
struct Student {
string name;
int age;
float grade;
};
int main() {
Student student1; // 没有初始化
cout << "Name: " << student1.name << endl; // 未定义,可能为垃圾值
cout << "Age: " << student1.age << endl; // 未定义,可能为垃圾值
cout << "Grade: " << student1.grade << endl; // 未定义,可能为垃圾值
return 0;
}
4. 结构体的传递
4.1 传值调用
当将结构体作为参数传递给函数时,默认是通过值传递的。这样会创建结构体的副本,修改副本不会影响原结构体。
#include <iostream>
using namespace std;
struct Student {
string name;
int age;
float grade;
};
void printStudent(Student student) {
// 修改副本
student.name = "Changed Name";
cout << "Student Name: " << student.name << endl;
}
int main() {
Student student1 = {"Tom", 20, 85.5};
printStudent(student1); // 传递副本
cout << "Original Name: " << student1.name << endl; // 原始结构体未改变
return 0;
}
4.2 传引用调用
为了避免复制结构体带来的开销,或者希望函数内修改结构体内容时影响原结构体,可以通过引用传递的方式来传递结构体。
#include <iostream>
using namespace std;
struct Student {
string name;
int age;
float grade;
};
void updateStudent(Student &student) {
student.name = "Updated Name"; // 修改原始结构体
}
int main() {
Student student1 = {"Tom", 20, 85.5};
updateStudent(student1); // 传递引用
cout << "Updated Name: " << student1.name << endl; // 原始结构体已改变
return 0;
}
4.3 传指针调用
还可以通过指针传递结构体,这样可以避免复制结构体并且能够修改原始数据。传递指针需要使用*
来解引用。
#include <iostream>
using namespace std;
struct Student {
string name;
int age;
float grade;
};
void updateStudent(Student *student) {
student->name = "Updated by Pointer"; // 使用指针修改
}
int main() {
Student student1 = {"Tom", 20, 85.5};
updateStudent(&student1); // 传递指针
cout << "Updated Name: " << student1.name << endl; // 原始结构体已改变
return 0;
}
5. 结构体数组
C++中可以定义结构体数组,这样可以存储多个相同类型的结构体。结构体数组可以用来表示同类事物的集合,比如多个学生的信息。
示例:学生信息数组
#include <iostream>
using namespace std;
struct Student {
string name;
int age;
float grade;
};
int main() {
// 创建一个包含3个学生的结构体数组
Student students[3] = {
{"Tom", 20, 85.5},
{"Alice", 22, 90.0},
{"Bob", 19, 88.5}
};
// 输出所有学生信息
for (int i = 0; i < 3; i++) {
cout << "Name: " << students[i].name << ", Age: " << students[i].age
<< ", Grade: " << students[i].grade << endl;
}
return 0;
}
输出:
Name: Tom, Age: 20, Grade: 85.5
Name: Alice, Age: 22, Grade: 90
Name: Bob, Age: 19, Grade: 88.5
6. 结构体与指针
结构体与指针的结合使用是C++中的重要概念,可以通过指针高效地处理动态内存分配的结构体。
示例:结构体指针
#include <iostream>
using namespace std;
struct Student {
string name;
int age;
float grade;
};
int main() {
// 动态创建一个结构体
Student *studentPtr = new Student;
// 通过指针访问和修改结构体成员
studentPtr->name = "Tom";
studentPtr->age = 20;
studentPtr->grade = 85.5;
cout << "Name: " << studentPtr->name << endl;
cout << "Age: " << studentPtr->age << endl;
cout << "Grade: " << studentPtr->grade << endl;
// 删除动态分配的内存
delete studentPtr;
return 0;
}
解析:
1
. 使用new
动态创建结构体变量,返回的是结构体的指针。 2. 使用->
操作符访问结构体指针的成员。 3. 使用delete
释放动态分配的内存。
7. 结构体的高级应用
7.1 结构体作为函数返回值
C++支持结构体作为函数的返回值,这使得可以通过函数返回结构体数据。
#include <iostream>
using namespace std;
struct Point {
int x;
int y;
};
Point createPoint(int x, int y) {
Point p;
p.x = x;
p.y = y;
return p;
}
int main() {
Point p = createPoint(10, 20);
cout << "Point x: " << p.x << ", y: " << p.y << endl;
return 0;
}
7.2 结构体与类的关系
在C++中,struct
和class
有很多相似之处。唯一的区别是:
-
struct
的成员默认是公共的(public); -
class
的成员默认是私有的(private)。
#include <iostream>
using namespace std;
struct MyStruct {
int x; // public by default
};
class MyClass {
private:
int x; // private by default
public:
void setX(int val) {
x = val;
}
int getX() {
return x;
}
};
int main() {
MyStruct s;
s.x = 10; // 可以直接访问
MyClass c;
c.setX(20); // 通过公有函数访问
cout << "MyStruct x: " << s.x << endl;
cout << "MyClass x: " << c.getX() << endl;
return 0;
}
类详解(看不懂就不看了 结构体学会就行)
在C++中,类(class
)是面向对象编程(OOP)的核心概念之一。它是一种自定义的数据类型,用于描述一组具有相同特征和行为的对象。类是对象的蓝图或模板,它包含了对象的属性(数据成员)和行为(成员函数)。通过类,我们可以将现实世界的实体转化为代码中的对象,使得代码更加模块化、可扩展且易于维护。
1. 类的定义与使用
1.1 类的基本结构
在C++中,类通过class
关键字定义,类的定义包括以下几个部分:
-
类名:类的名称,通常遵循大驼峰命名法(如
Person
、Car
等)。 -
成员变量(属性):类的属性,用于存储对象的状态,通常是数据类型。
-
成员函数(行为):类的行为,用于定义对象能够执行的操作。
类的基本结构如下:
class 类名 {
public:
// 数据成员
数据类型 成员名1;
数据类型 成员名2;
// 构造函数
类名();
// 成员函数
void 成员函数1();
void 成员函数2();
};
示例:定义一个简单的Person
类
#include <iostream>
using namespace std;
class Person {
public:
// 数据成员
string name;
int age;
// 构造函数
Person(string n, int a) {
name = n;
age = a;
}
// 成员函数
void introduce() {
cout << "Hello, my name is " << name << " and I am " << age << " years old." << endl;
}
};
int main() {
// 创建对象并初始化
Person person1("Alice", 30);
person1.introduce();
return 0;
}
解释:
-
类的定义:
Person
类包含两个数据成员:name
(字符串类型)和age
(整数类型),以及一个成员函数introduce
,用于输出对象的介绍。 -
构造函数:
Person
类有一个带参数的构造函数,用于初始化对象的属性。 -
对象创建:在
main
函数中,创建了一个Person
类的对象person1
,并通过构造函数初始化其name
和age
。
输出:
Hello, my name is Alice and I am 30 years old.
2. 构造函数与析构函数
2.1 构造函数
构造函数是类的一种特殊成员函数,它在创建对象时自动调用,用于初始化对象的状态。构造函数的名称必须与类名相同,并且没有返回类型。
构造函数的类型有:
-
默认构造函数:不带任何参数的构造函数。
-
带参数构造函数:可以带参数的构造函数,用于在创建对象时传入初始值。
-
拷贝构造函数:用于通过另一个对象初始化当前对象。
示例:构造函数
#include <iostream>
using namespace std;
class Rectangle {
public:
int length;
int width;
// 默认构造函数
Rectangle() {
length = 5;
width = 3;
}
// 带参数构造函数
Rectangle(int l, int w) {
length = l;
width = w;
}
void displayArea() {
cout << "Area: " << length * width << endl;
}
};
int main() {
Rectangle rect1; // 调用默认构造函数
Rectangle rect2(10, 6); // 调用带参数构造函数
rect1.displayArea(); // 输出面积:15
rect2.displayArea(); // 输出面积:60
return 0;
}
2.2 析构函数
析构函数是类的一种特殊成员函数,用于在对象生命周期结束时进行资源清理。析构函数的名称与类名相同,但前面加一个波浪号~
,没有参数,也没有返回值。C++会在对象销毁时自动调用析构函数。
class MyClass {
public:
MyClass() {
cout << "Constructor called" << endl;
}
~MyClass() {
cout << "Destructor called" << endl;
}
};
int main() {
MyClass obj; // 创建对象时调用构造函数
return 0; // 程序结束时,调用析构函数
}
输出:
Constructor called
Destructor called
3. 类的成员函数
类的成员函数定义了类的行为,成员函数可以访问和修改类的成员变量。
3.1 成员函数的定义与调用
成员函数可以在类内部定义,也可以在类外部定义。成员函数通过对象来调用。
示例:类的成员函数
#include <iostream>
using namespace std;
class Circle {
private:
float radius;
public:
// 构造函数
Circle(float r) {
radius = r;
}
// 成员函数
float getArea() {
return 3.14 * radius * radius;
}
void setRadius(float r) {
radius = r;
}
};
int main() {
Circle circle1(5); // 创建对象并初始化半径
cout << "Area: " << circle1.getArea() << endl; // 调用成员函数
circle1.setRadius(10); // 设置新的半径
cout << "Updated Area: " << circle1.getArea() << endl; // 调用成员函数
return 0;
}
3.2 常成员函数
常成员函数(const
成员函数)是指不会修改类成员变量的成员函数。常成员函数的声明中使用const
关键字。
class Student {
private:
string name;
public:
Student(string n) : name(n) {}
// 常成员函数
void printName() const {
cout << "Name: " << name << endl;
}
};
4. 访问控制:public
、private
、protected
类中的数据成员和成员函数的访问控制由访问控制符来控制,常用的访问控制符有:
-
public
:公共成员,任何函数或对象都可以访问。 -
private
:私有成员,只有类的成员函数才能访问,外部无法直接访问。 -
protected
:保护成员,类本身及其派生类可以访问,外部无法直接访问。
示例:访问控制
class Account {
private:
double balance;
public:
Account(double initial_balance) {
balance = initial_balance;
}
void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
double getBalance() const {
return balance;
}
};
int main() {
Account acc(1000);
acc.deposit(500);
acc.withdraw(200);
cout << "Account balance: " << acc.getBalance() << endl; // 1300
return 0;
}
5. 类的继承与多态(简要)
5.1 继承
继承是面向对象的一个重要特性,它允许我们在已有的类基础上创建新的类,新的类称为派生类(derived class
),继承自基类(base class
)的属性和方法。
class Animal {
public:
void eat() {
cout << "Eating..." << endl;
}
};
class Dog : public Animal {
public:
void bark() {
cout << "Barking..." << endl;
}
};
int main() {
Dog dog;
dog.eat(); // 从Animal继承的成员
dog.bark(); // Dog类自己的成员
return 0;
}
5.2 多态
多态是指相同的操作作用于不同的对象时,产生不同的结果。它通常通过虚函数实现。虚函数允许派生类重写基类中的方法,从而在运行时动态决定调用哪个函数。
class Shape {
public:
virtual void draw() {
cout << "Drawing a shape" << endl;
}
};
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing a circle" << endl;
}
};
int main() {
Shape* shape = new Circle();
shape->draw(); // 输出:Drawing a
circle delete shape;
return 0;
}
练习
练习题:学生信息管理
题目描述:
请设计一个结构体来管理学生的基本信息,要求实现以下功能:
-
定义一个
Student
结构体,其中包含以下数据成员:-
name
:学生姓名,字符串类型。 -
age
:学生年龄,整数类型。 -
score
:学生成绩,浮点数类型。
-
-
创建一个
Student
类型的数组,用于存储多名学生的基本信息。 -
通过键盘输入学生的姓名、年龄和成绩,将信息存储到结构体数组中。
-
显示所有学生的基本信息,包括姓名、年龄和成绩。
-
计算并输出所有学生的平均成绩。
输入输出示例:
输入:
请输入学生人数: 2
请输入学生姓名: Alice
请输入学生年龄: 20
请输入学生成绩: 90.5
请输入学生姓名: Bob
请输入学生年龄: 22
请输入学生成绩: 85.0
输出:
学生信息:
姓名: Alice, 年龄: 20, 成绩: 90.5
姓名: Bob, 年龄: 22, 成绩: 85.0
平均成绩: 87.75
提示:
-
可以使用
struct
来定义学生信息结构体。 -
使用数组存储多个学生的信息。
-
使用循环输入学生信息并输出。
题解:
我们可以按照以下步骤来实现这个练习:
-
定义结构体:首先,定义一个
Student
结构体,包含name
、age
和score
三个成员。 -
输入学生信息:通过循环输入多个学生的信息,并将这些信息存储到一个
Student
类型的数组中。 -
输出学生信息:遍历结构体数组,输出每个学生的信息。
-
计算平均成绩:遍历结构体数组,计算所有学生成绩的平均值并输出。
代码实现:
#include <iostream>
#include <string>
using namespace std;
// 定义学生结构体
struct Student {
string name; // 学生姓名
int age; // 学生年龄
float score; // 学生成绩
};
int main() {
int n;
// 输入学生人数
cout << "请输入学生人数: ";
cin >> n;
// 创建结构体数组
Student students[n];
// 输入学生信息
for (int i = 0; i < n; i++) {
cout << "请输入学生姓名: ";
cin >> students[i].name;
cout << "请输入学生年龄: ";
cin >> students[i].age;
cout << "请输入学生成绩: ";
cin >> students[i].score;
}
// 输出所有学生信息
cout << "\n学生信息:" << endl;
for (int i = 0; i < n; i++) {
cout << "姓名: " << students[i].name
<< ", 年龄: " << students[i].age
<< ", 成绩: " << students[i].score << endl;
}
// 计算平均成绩
float totalScore = 0;
for (int i = 0; i < n; i++) {
totalScore += students[i].score;
}
float averageScore = totalScore / n;
// 输出平均成绩
cout << "\n平均成绩: " << averageScore << endl;
return 0;
}
代码说明:
-
结构体定义:首先定义了一个
Student
结构体,包含name
、age
和score
成员,分别表示学生的姓名、年龄和成绩。 -
数组存储学生信息:通过输入学生人数,创建一个
Student
类型的数组,数组大小为n
,用来存储每个学生的信息。 -
输入学生信息:使用
for
循环输入每个学生的姓名、年龄和成绩,存储在结构体数组中。 -
输出学生信息:使用
for
循环遍历结构体数组,输出每个学生的基本信息。 -
计算平均成绩:通过遍历数组,累加所有学生的成绩,最后计算平均成绩并输出。
示例执行过程:
请输入学生人数: 2
请输入学生姓名: Alice
请输入学生年龄: 20
请输入学生成绩: 90.5
请输入学生姓名: Bob
请输入学生年龄: 22
请输入学生成绩: 85.0
学生信息:
姓名: Alice, 年龄: 20, 成绩: 90.5
姓名: Bob, 年龄: 22, 成绩: 85.0
平均成绩: 87.75
练习重点:
-
结构体的定义和使用。
-
如何通过结构体数组存储多个学生的信息。
-
如何遍历结构体数组并进行输出。
-
如何计算平均成绩。