本章学习结构体与运算符重载。
在各路题目中,我们有时候会看到,一个主体有很多个属性。比如你是一个学生,你可以被拆分为以下属性的集合体:
- 姓名
- 性别
- 年龄
- 年级
- 班级
……
而且,其余的学生也都是跟你一样有这些属性。那么,我们现在假设一个年级有1000人,难道我们要针对每个属性都开一个1000单位的数组吗?
这时候我们就可以使用结构体,把这些属性整合,产生一个新的类型。
比如上文中的属性,我们就可以整合为一个student类型。写法如下:
1 | struct student//struct是必须的,不可更改;后面的student则可以自定义 |
通过上文的代码段,我们就建立了一个结构体类型,类型名称为student。其下属有5个变量,我们称之为“成员变量”,又叫“成员表”;还有1个函数,我们称之为“成员函数”。
这样,我们就可以总结一个格式:
1 | struct 类型名称 |
没有严格的顺序,但一般成员函数写在成员表之后,因为变量/数组等必须先定义才能调用。
注意结构体的右大括号后必须有个分号,不要漏掉。
那么,我们如何使用结构体?
结构体类型,俗称自定义类型。因此,可以效仿其它类型的定义方法。如上文中的student,此时就可以用作数据类型。如,我们称int a;
为定义一个名为a的int类型变量。同样的,我们可以student a;
来定义一个名为a的student类型变量。
因此,我们可以写出如下代码:1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
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
9struct student
{
string name;
int age;
void show()
{
cout<<name<<” ”<<age <<endl;
}
}a;
则我们可以通过“.”,就是跟小数点一样的那个点,来访问结构体变量的成员。
示例:
1 |
|
如上示例中,我们可以通过“.”来访问结构体变量的成员。此时“.”叫做“成员访问符”。访问到成员变量或成员数组或成员函数的时候,可以如同一般的变量/数组/函数一般使用。
对于结构体类型,我们还可以对其进行运算符重载。
如,设有以下结构体类型及变量定义:
1 | struct complex//complex表示复数 |
显然,我们不能直接使用+号来做到z=x+y;只能分别写z.a=x.a+y.a;和z.b=x.b+y.b;这样就显得很繁琐。
那么,该如何才能用+号直接操作呢?
我们可以在struct complex中进行对于+号的重载,格式如下:
1 | struct complex//complex表示复数 |
这样就可以在程序的其余位置,对complex类型的变量使用+号直接操作了。
同理,除加号外,“-”,“*”,“/”,“%”也可以采用这样的方式重载,格式为:
1 | friend 类型名 operator 符号(const 类型名& a,const 类型名& b) |
以上,是对算术运算符的重载。
再设有以下结构体类型及变量定义:1
2
3
4struct student
{
double chinese,math;//用来表示语文成绩和数学成绩
}a,b;
这样虽然可以使用==和!=来判断a和b是否相等(所有成员变量的值完全相同与否),但不能直接使用大于号或小于号来判断a和b谁大谁小,因为它不知道要用哪个来判断。所以我们需要重载一下,告诉程序怎么处理。示例:1
2
3
4
5
6
7
8
9struct 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 | friend bool operator 符号(const 类型名& a,const 类型名& b) |
以上,是对逻辑运算符的重载。
再设有以下结构体类型及变量定义:1
2
3
4
5struct 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
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 | friend istream& operator >>(istream& in,类型名& x) |
对输出重载:1
2
3
4
5friend ostream& operator <<(ostream& out,类型名& x)
{
out<<变量1<<” “<<变量2;//可以更多
return out;
}
以上,是对输入输出运算符的重载。
还可以对=,(),[],->四种运算符进行重载,但这已经严重超纲,有兴趣的同学可以自行百度一下。
第九章到此结束。