1.C++中结构体与类的区别
在C语言中,结构体不能包含函数。C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能。
struct能包含成员函数;struct能继承;struct能实现多态等 。既然这些它都能实现,那它和class还能有什么区别呢?
最本质的一个区别就是默认的访问控制:默认的继承访问权限。struct是public的,class是private的。
struct A
{
char a;
};
struct B : A
{
char b;
};
这个时候B是public继承A的。
如果都将上面的struct改成class,那么B是private继承A的。这就是默认的继承访问权限。
所以我们在平时写类继承的时候,通常会这样写:
class B : public A
就是为了指明是public继承,而不是用默认的private继承。
当然,到底默认是public继承还是private继承,取决于子类而不是基类。 struct可以继承class,同样class也可以继承struct,那么默认的继承访问权限是看子类到底是用的struct还是class。如下:
struct A{};class B : A{}; //private继承
struct C : B{}; //public继承
struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的。
当然,在这里还要强调一点的就是,对于访问控制,应该在程序里明确的指出,而不是依靠默认,这是一个良好的习惯,也让代码更具可读性。
其他区别:
(1)“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数。
(2)C++ 中的struct是对C中的struct的扩充,既然是扩充,那么它就要兼容过去C中struct应有的所有特性。也就是说struct可以在定义的时候用{}赋初值,而class不行。因为将struct改成class的时候,访问控制由public变为 private了,那当然就不能用{}来赋初值了。
struct A //定义一个struct
{
char c1;
int n2;
double db3;
};
A a={'p', 7, 3.1415926}; //定义时直接赋值
事实上,是因为加入这样的函数,使得类的内部结构发生了变化。向上面的struct中加入一个构造函数(或虚函数),可以发现struct也不能用{}赋初值,但加入一个普通函数,仍然可以用{}赋值。事实上,是因为加入构造函数(或虚函数)这样的函数,使得类的内部结构发生了变化。 那么,看到这里,我们发现即使是struct想用{}来赋初值,它也必须满足很多的约束条件,这些条件实际上就是让struct更体现出一种数据机构而不是类的特性。
总结:到底是用struct还是class,完全看个人的喜好,你可以将程序里所有的class全部替换成struct,它依旧可以很正常的运行。从上面的区别,我们可以看出,struct更适合看成是一个数据结构的实现体,class更适合看成是一个对象的实现体。
2.定义、声明、初始化
#include <iostream> //引用库函数
using namespace std; //使用命名空间
//定义一个名为inflatable的结构体
struct inflatable
{
char name[20];
float volume;
double price;
};
//定义一个没有名字的结构体的同时,声明了两个该类型的变量stud1,stud2.每个变量的其中一个成员也是一个结构体inflatable.
struct {
int num;
char sex;
inflatable inf;
}stud1,stud2;
//定义一个名字为student的结构体的同时,声明了两个该类型的变量stud1,stud2.每个变量的其中一个成员也是一个结构体inflatable.
struct student{
int num;
char sex;
inflatable inf;
}stud3,stud4;
int main() //主函数,程序执行的入口
{
//声明一个结构体变量并作初始化
inflatable in1={"Li Ming",2.0,9};
//定义结构体数组的同时初始化
inflatable guests[2]={
{"Bambi",0.5,21.55},
{"Goodzilla",2000,654.214}
};
return 0;
}
3.结构体与函数
结构型数据的成员作为函数的参数
考虑下面的结构体
struct student{
int num;
char sex;
char name[20];
float score;
}stud;
假设有若干函数,其函数原型为:
void f1(int);
void f2(float);
void f3(char *);
那么下面的函数调用是合法的:
f1(stud.num);
f2(stud.socre);
f3(stud.name);//传递数组stud.name的值,即第一个元素的地址
f1(stud.name[2]);
如果要将结构型数据的成员的地址传递给函数,就必须在表示结构成员的表达式前使用取地址运算符&;同时,函数的形参也应该是指针类型或者数组类型。例如,假设另有两个函数的原型如下:
void f4(int *);
void f5(float *);
那么,下面的调用形式是正确的:
f3(stud.name);//传递数组stud.name的值,即第一个元素的地址
f3(&stud.name[2]);//传递数组stud.name[2]的地址
f4(&stud.num);//传递成员stud.num的地址
f5(&stud.score);
注:运算符&放在结构型数据名前,而不是放在成员名之前。数组名name本身就是数组的首地址,相应的结构名前不需要使用&。
结构型数据作为函数的参数或返回值
一般情况下,由于结构体变量的成员较多,占用内存也较多,传送时需要消耗大量时间和空间,不建议使用值传递的方式。
常用的方法是采用引用传递或者传递指针参数。采用这两种方法,不需要对实参的成员进行复制,仅传递结构的地址,占用内存少,调用速度快,具有较高的效率。
例如,函数原型为:
void f7(student &s);
void f8(student *s);
相应的调用形式为:
f7(stud);
f8(&stud);
结构体也可以作为函数的返回值,例如:
student * func1(void);//返回函数指针
student func2(void);//返回结构体类型变量
4.结构体与数组
定义结构体数组
和定义结构体变量类似,定义结构体数组时只需声明其为数组即可。如:
struct Student{
int num;
char name[20];
char sex[5];
int age;
float score;
};
Student stu[3]; //定义Student类型的数组stu
//或在定义结构体的同时声明数组
struct Student{
...
}stu[3];
//声明的同时还可以初始化
struct Student{
int num;
char name[20];
char sex[5];
int age;
float score;
}stu[2]={
{110,"Zhang",'M',24,90},
{111,"Li",'M',23,93}
};
假设有两个函数,其原型如下:
void display(const Student[],int);
void sortArray(Student[],int);
上述两个函数都可以接收结构体数组,其中display函数的形参是const类型,只是访问而不修改实参结构体数组,而sortArray函数会修改实参。
5.结构体与指针
结构体指针(结构指针)
结构指针是指指向一个结构体变量的指针。
例如,定义一个结构体指针pStud,并让它指向结构体stud:
Student * pStud,stud;
pStud=&stud;
有了结构体指针,就可以用它方便地访问它所指向的结构变量的各个成员。下面三种访问形式等效:
//结构体指针对结构体中元素的访问需要用“->”访问
pStud->num;
//结构体变量用“.”访问相应的结构体元素
(*pStud).num;
stud.num;
结构数组与指向结构的指针
结构指针可指向结构体数组,它的值是该结构体数组的首地址。假设ps为指向结构体数组的指针变量,则ps也指向该结构体数组的0号元素,ps+1指向1号元素,ps+i指向i号元素。这与普通数组一致。
例如:
struct Student{
int num;
char name[20];
char sex[5];
int age;
float score;
}stu[2]={
{110,"Zhang",'M',24,90},
{111,"Li",'M',23,93},
{112,"Wangle",'M',33,43}
};
void display(const Student* const);
Student *pStud=stu;
for(int i=0;i<3;i++)
display(pStud++);
注意:一个结构指针可以用来访问结构体变量或结构体数组的成员,但是不能让它指向结构成员。例如:
pStud=&stu[1].name;//错误
pStud=stu;//正确,赋予数组首地址
pStud=&stu[0];//正确,赋予0号元素首地址