1.结构体
结构体是一种特殊形态的类,它和类一样,可以有自己的数据成员和函数成员,可以有自己的构造函数和析构函数,可以控制访问权限,可以继承,支持包含多态,结构体定义的语法和类的定义语法几乎一样。结构体和类的唯一区别在于,结构体和类具有不同的默认访问控制属性:在类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private);在结构体中,对于未指定任何访问控制属性的成员,其访问控制属性为公有类型(public)。因此,在结构体定义中,如果把公有成员放在最前面,则最前面的“public:”可以省去,结构体可以按照如下语法定义:
struct 结构体名称
{
公有成员
protected:
保护型成员
private:
私有成员
};
虽然结构体和类的功能完全相同,只是在形式上有细微的差异,但是为了保持和C程序的兼容性,C++还要引入结构体。
C语言只有结构体,而没有类,C语言结构体中只允许定义数据成员,不允许定义函数成员,而且C语言没有访问控制属性的概念,结构体的全部成员是公有的。C语言的结构体是为面向过程的程序服务的,并不能满足面向对象程序设计的要求,因此C++为C语言的结构体引入了成员函数、访问权限控制、继承、包含多态等面向对象特性。但由于用structure一词来表示这种具有面向对象特性的抽象数据类型不再贴切,另外C语言中struct所留下的根深蒂固的影响,C++在struct之外引入了另外的关键字——class,并且把它作为定义抽象数据类型的首选关键字。但为了保持和C程序的兼容性,C++保留了struct关键字,并规定结构体的默认访问控制权限为公有类型。
类和结构体并存,在编写C++程序时,是否还需要使用结构体是一个代码风格的问题,如果完全不使用结构体也丝毫不会影响程序的表达能力。
与类不同,对于结构体,人们习惯将数据成员设置为公共的。有时在程序中需要定义一些数据类型,它们并没有声明操作,定义它们的目的只是将一些不同类型的数据组合成一个整体,从而方便地保村数据,这样的类型不妨定义为结构体。如果用类来定义,为了遵循“将数据成员设置为私有”的习惯,需要为每个数据成员编写专门的函数成员来读取和改写各个属性,反而比较麻烦。
如果一个结构体的全部数据成员都是公共的,并且没有用户定义的构造函数,没有基类和虚函数,这个结构体的变量可以用下面的语法形式赋初值:
类型名 变量名={成员数据1初值,成员数据2初值,...};
在语言规则上,满足以上条件的类对象也可以用同样的方式赋初值,不过由于习惯将类的数据成员设置为私有的,因此类一般不满足以上条件。通过以上形式为结构体变量初始化,是使用结构体的另一个方便之处。
【例】用结构体表示学生信息
#include<iostream>
using namespace std;
struct Student //学生信息结构体
{
int num;//学号
string name;//姓名,字符串对象
char sex;//性别
int age;//年龄
};
int main()
{
Student stu = { 1001,"张三",'M',23 };
cout << "Num:" << stu.num << endl;
cout << "Name:" << stu.name << endl;
cout << "Sex:" << stu.sex << endl;
cout << "Age:" << stu.age << endl;
return 0;
}
运行结果:
本程序中,Student结构体中有的成员是string类型的,string是标准C++中预定义的一个类,专用于存放字符串。
1.联合体
有时,一组数据中任何两个数据不会同时有效。例如,如果需要存储一个学生的各门课程的成绩,有些课程是等级制的,需要用一个字符来存储它的等级,有些课程只记“通过”和“不通过”,需要用一个布尔值来表示是否通过,而另一些课程的成绩是百分制的,需要用一个整数来存储它的分数,这个课程的成绩就可以用一个联合体来表示。
联合体是一种特殊形态的类,它可以有自己的数据成员和函数成员,可以有自己的构造函数和析构函数,可以控制访问权限。与结构体一样,联合体也是C语言继承而来的,因此它的默认访问控制权限也是公有类型的。**联合体的全部数据成员共享同一组内存单元。**联合体定义的语法形式如下:
union 联合体名称
{
公有成员
protected:
保护型成员
private:
私有成员
};
例如,成绩这个联合体可以声明如下:
union Mark
{
char grade;//等级制的成绩
bool pass;//只记是否通过的成绩
int percent;//百分制成绩
};
联合体Mark的类型变量的存储结构如下图所示:
正是由于联合体的成员共用相同的内存单元,联合体变量中的成员同时至多只有一个是有意义的。另外,不同数据单元共用相同内存单元的特性,联合体有下面一些限制:
(1)联合体的各个对象成员,不能有自定义的构造函数、自定义的析构函数和重载的拷贝赋值运算符,不仅联合体的对象成员不能有这些函数,这些对象成员的对象成员也不能有。
(2)联合体不能继承,因而也不支持包含多态。
一般只用联合体来存储一些公有数据,而不为它定义函数成员。
联合体可以不声明名称,称为无名联合体。无名联合体没有标记名,只是声明一个成员项的集合,这些成员项具有相同的内存地址,可以由成员项的名字直接访问。
例如,声明无名联合体如下:
union
{
int i;
float f;
};
在程序中可以这样使用:
i=10;
f=2.2;
无名联合体通常用作类或结构体的内嵌成员
【例】使用联合体保存成绩信息,并且输出
class ExamInfo
{
public:
//3种构造函数,分别用等级、是否通过和百分制来初始化
ExamInfo(string name, char grade) :m_name(name), mode(GRADE), m_grade(grade) {}
ExamInfo(string name,bool pass):m_name(name), mode(PASS),m_pass(pass){}
ExamInfo(string name, int percent):m_name(name), mode(PERCENTAGE),m_percent(percent){}
void Show();
private:
string m_name; //课程名称
enum
{
GRADE,
PASS,
PERCENTAGE
}mode; //采用哪种计分方式
union
{
char m_grade; //等级制的成绩
bool m_pass; //是否通过
int m_percent; //百分制的成绩
};
};
void ExamInfo::Show()
{
cout << m_name << ":";
switch (mode)
{
case GRADE:
cout << m_grade;
break;
case PASS:
cout << (m_pass ? "Pass" : "Fall");
break;
case PERCENTAGE:
cout << m_percent;
break;
}
cout << endl;
}
int main()
{
ExamInfo c1("English", 'B');
ExamInfo c2("Chinese", true);
ExamInfo c3("C++程序设计", 85);
c1.Show();
c2.Show();
c3.Show();
return 0;
}
运行结果: