C++语言-9-结构体与运算符重载

本章学习结构体与运算符重载。


在各路题目中,我们有时候会看到,一个主体有很多个属性。比如你是一个学生,你可以被拆分为以下属性的集合体:

  1. 姓名
  2. 性别
  3. 年龄
  4. 年级
  5. 班级
    ……

而且,其余的学生也都是跟你一样有这些属性。那么,我们现在假设一个年级有1000人,难道我们要针对每个属性都开一个1000单位的数组吗?

这时候我们就可以使用结构体,把这些属性整合,产生一个新的类型。

比如上文中的属性,我们就可以整合为一个student类型。写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
struct student//struct是必须的,不可更改;后面的student则可以自定义
{
string name;//用一个名为name的字符串保存姓名
char sex;//假设我们用M和W来表示Man和Woman,那么可以用一个字符型来保存
int age;
int grade;
int class;//分别用三个int类型变量来保存年龄,年级和班级
void show()
{
cout<<name<<” ”<<sex<<” ”<<age<<” ”<<grade<<” “<<class<<endl;
}//该函数可以输出5个变量
};//注意这里有个分号,不要漏了

通过上文的代码段,我们就建立了一个结构体类型,类型名称为student。其下属有5个变量,我们称之为“成员变量”,又叫“成员表”;还有1个函数,我们称之为“成员函数”。

这样,我们就可以总结一个格式:

1
2
3
4
5
struct 类型名称
{
成员表
成员函数
};

没有严格的顺序,但一般成员函数写在成员表之后,因为变量/数组等必须先定义才能调用。
注意结构体的右大括号后必须有个分号,不要漏掉。

那么,我们如何使用结构体?

结构体类型,俗称自定义类型。因此,可以效仿其它类型的定义方法。如上文中的student,此时就可以用作数据类型。如,我们称int a;为定义一个名为a的int类型变量。同样的,我们可以student a;来定义一个名为a的student类型变量。

因此,我们可以写出如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<string>
using namespace std;
struct student
{
string name;
int age;
};
int main()
{
student a,b;//定义两个student类型的变量,分别名为a和b
return 0;
}

定义student类型的变量也可以写在struct student的右大括号后分号前。写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<string>
using namespace std;
struct student
{
string name;
int age;
}a,b;//定义两个student类型的变量,分别名为a和b
int main()
{

return 0;
}

如果采取上述方法定义结构体变量,还可以不写结构体类型的类型名称。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<string>
using namespace std;
struct
{
string name;
int age;
}a,b;//定义两个student类型的变量,分别名为a和b
int main()
{

return 0;
}

此时该结构体类型是一次性类型,因为没有填写结构体类型名称,所以不可以被再次使用。

讲完了结构体类型变量的定义,现在我们来讲一下如何访问结构体变量的成员。

假设我们有如下结构体及变量定义:

1
2
3
4
5
6
7
8
9
struct student 
{
string name;
int age;
void show()
{
cout<<name<<” ”<<age <<endl;
}
}a;

则我们可以通过“.”,就是跟小数点一样的那个点,来访问结构体变量的成员。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<string>
using namespace std;
struct student
{
string name;
int age;
void show()
{
cout<<name<<” ”<<age <<endl;
}
}a;
int main()
{
cin>>a.name>>a.age;//分别输入student类型变量a的成员变量name和age
a.show();//调用student类型变量a的成员函数show
return 0;
}

如上示例中,我们可以通过“.”来访问结构体变量的成员。此时“.”叫做“成员访问符”。访问到成员变量或成员数组或成员函数的时候,可以如同一般的变量/数组/函数一般使用。

对于结构体类型,我们还可以对其进行运算符重载。

如,设有以下结构体类型及变量定义:

1
2
3
4
struct complex//complex表示复数
{
int a,b;//a表示实部,b表示虚部
}x,y,z;

关于复数

显然,我们不能直接使用+号来做到z=x+y;只能分别写z.a=x.a+y.a;和z.b=x.b+y.b;这样就显得很繁琐。

那么,该如何才能用+号直接操作呢?

我们可以在struct complex中进行对于+号的重载,格式如下:

1
2
3
4
5
6
7
8
9
10
11
struct complex//complex表示复数
{
int a,b;//a表示实部,b表示虚部
friend complex operator +(const complex& p,const complex& q)
{
complex ans;
ans.a=p.a+q.a;
ans.b=p.b+q.b;
return ans;
}
}x,y,z;

这样就可以在程序的其余位置,对complex类型的变量使用+号直接操作了。

同理,除加号外,“-”,“*”,“/”,“%”也可以采用这样的方式重载,格式为:

1
2
3
4
friend 类型名 operator 符号(const 类型名& a,const 类型名& b)
{

}

以上,是对算术运算符的重载。

再设有以下结构体类型及变量定义:

1
2
3
4
struct student
{
double chinese,math;//用来表示语文成绩和数学成绩
}a,b;

这样虽然可以使用==和!=来判断a和b是否相等(所有成员变量的值完全相同与否),但不能直接使用大于号或小于号来判断a和b谁大谁小,因为它不知道要用哪个来判断。所以我们需要重载一下,告诉程序怎么处理。示例:

1
2
3
4
5
6
7
8
9
struct student
{
double chinese,math;//用来表示语文成绩和数学成绩
friend bool operator >(const student& p,const student& q)
{
if(p.chinese!=q.chinese) return p.chinese>q.chinese;
return p.math>q.math;
}
}a,b;

这样就可以使得大于号能判断a和b的大小(小于号还是不行):在判断是否a>b时,先判断a的语文成绩是否比b高,若是则a大;若语文成绩相等则判断数学成绩,若a数学成绩较高则a大;数学成绩也相等则a不比b大。

同理,可以对其它逻辑符号进行重载,格式为:

1
2
3
4
friend bool operator 符号(const 类型名& a,const 类型名& b)
{

}

以上,是对逻辑运算符的重载。

再设有以下结构体类型及变量定义:

1
2
3
4
5
struct student 
{
string name;
int age;
}a;

这样我们是不能使用cin和cout直接输入和输出的,需要重载流插入符合流输出符才行。示例:

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
#include<iostream>
#include<string>
using namespace std;
struct student
{
string name;
int age;
friend istream& operator >>(istream& in,student& x)
{
in>>x.name>>x.age;
return in;
}//对输入的重载,使得可以使用cin直接输入student类型的变量
friend ostream& operator <<(ostream& out,student& x)
{
out<<x.name<<" "<<x.age;
return out;
}//对输出的重载,使得可以使用cout直接输出student类型的变量
//为了符合一般的使用习惯,endl一般不写在对<<的重载中
}a;
int main()
{
cin>>a;
cout<<a<<endl;
return 0;
}

以上便是对输入和输出的重载。格式为:

对输入重载:

1
2
3
4
5
friend istream& operator >>(istream& in,类型名& x)
{
in>>变量1>>变量2;//可以更多
return in;
}

对输出重载:

1
2
3
4
5
friend ostream& operator <<(ostream& out,类型名& x)
{
out<<变量1<<” “<<变量2;//可以更多
return out;
}

以上,是对输入输出运算符的重载。

还可以对=,(),[],->四种运算符进行重载,但这已经严重超纲,有兴趣的同学可以自行百度一下。

第九章到此结束。

--It's the end.Thanks for your read.--