深入了解C++ 结构体(struct)与共用体(union)

 更新时间:2020年08月11日 11:50:40   作者:Dabelv  
这篇文章主要介绍了C++ 结构体与共用体的的相关资料,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下

编码运行环境:VS2017+Win32+Debug,Win32表示生成32bits的应用程序。

结构体(struct)与共用体(union)是C语言中就已经存在的数据类型,C++对他们进行了扩充,最大的变化是允许在结构和公用体中定义成员函数。下面将通过实例讲解二者的特性和用法。

1.struct

以下是一个使用了结构体的C++程序。

#include <iostream>
using namespace std;

struct Room
{
		int floor;
		int No;
};

struct Student
{
	int age;
	int score;
	Student(int a,int s){
		age=a;
		score=s;
	}
};

int main(int argc,char* argv[])
{

	Room r[3]={{1,101},{2,201},{3,301}};
	Student s(18,89);
	cout<<"the room are:";
	cout<<r[0].floor<<"-"<<r[0].No<<" ";
	cout<<r[1].floor<<"-"<<r[1].No<<" ";
	cout<<r[2].floor<<"-"<<r[2].No<<endl;
	cout<<"the student's age:"<<s.age<<" score:"<<s.score<<endl;
	getchar();
}

程序运行结果:

the room are:1-101 2-201 3-301
the student's age:18 score:89

阅读以上程序,在C++中使用结构体需要注意以下几点:

 (1)C++中,结构体是一种真正的数据类型,在利用结构定义变量时,不需要像在C中带上struct关键字,或先使用typedef struct structname structalias的方式进行申明。

(2)C++对C中的struct进行了扩充,允许在struct中定义成员函数。struct中的成员变量和成员函数也有访问权限,在class中,默认的访问权限是private,而在struct中默认访问权限是public,这是结构体和类的唯一区别。struct成员的默认访问权限设为public是C++保持与C语言兼容而采取的一项策略。

(3)如果struct中没有显示定义任何构造函数,那么结构变量可以像在C语言中那样用花括号顺序指明数据成员的值来进行初始化。但是一旦显示定义了任何一个构造函数,就不能用这种方式初始化了。如果在class中只有若干public型的数据成员,而没有显示定义任何构造函数,也可以使用花括号进行初始化。

(4)用sizeof运算符计算结构的大小时,要考虑结构体内部变量的对齐问题。

2.union

共用体(union),又名联合体,是一种特殊的类,从C语言章继承而来,其基本语义没有发生什么变化,只是具有了类的一些特性(允许定义成员函数)。在实际的编程实践中,使用频率没有struct高。与struct相比,最显著的区别是union的数据成员共享同一段内存,以达到节省空间的目的。

2.1union的基本性质

通过如下程序考察union变量的占用空间,成员赋值时的相互影响。

#include <iostream>
using namespace std;
union testunion
{
	char c;
	int i;
};

int main(int argc,char* argv[])
{
	cout<<sizeof(testunion)<<endl;
	testunion* pt=new testunion;
	char* p=reinterpret_cast<char*>(pt);
	for(int i=0;i<sizeof(*pt);i++)
		cout<<int(p[i])<<" ";
	cout<<endl;
	cout<<pt->i<<endl;
	pt->c='A';
	cout<<pt->c<<endl;
	for(int i=0;i<sizeof(*pt);i++)
		cout<<int(p[i])<<" ";
	cout<<endl;
	cout<<pt->i<<endl;
	delete pt;
}

程序运行结果:

4
-51 -51 -51 -51
-842150451
A
65 -51 -51 -51
-842150591

可以看出,union testunion变量的体积是4,它是由两个数据成员中体积较大的一个(int)类型来决定的。对其中一个数据成员的修改,一定会同时改变所有其他数据成员的值。不过对体积较小的数据成员的修改,只会影响到该成员应该占用的那些字节,对超出部分(高位字节)没有什么影响。

2.2union的高级特性

观察如下程序。

#include <iostream>
using namespace std;
struct Student
{
	int age;
	int score;
	Student(int a,int s)
	{
		age=a;
		score=s;
	}
};

union testunion
{
	char c;
	int i;
};

class someClass
{
	int num;
public:
	void show(){cout<<num<<endl;}
};

union A
{
	char c;
	int i;
	double d;
	someClass s;
};

union B
{
	char c;
	int i;
	double d;
	B(){d=8.9;}
};

union
{
	char c;
	int i;
	double d;
	void show(){cout<<c<<endl;}
}u={'U'};

int main(int argc,char* argv[])
{
	A a={'A'};
	B b;
	cout<<a.c<<endl;
	cout<<b.d<<endl;
	a.s.show();
	u.show();
	
	//匿名共用体
	union
	{
		int p;
		int q;
	};

	p=3;
	cout<<q<<endl;
}

程序运行结果:

A
8.9
65
U
3

阅读以上程序,需要注意以下几点:

 (1)union可以指定成员的访问权限,默认情况下,与struct具有一样的权限(public)。

 (2)union也可以定义成员函数,包括构造函数和析构函数。与struct不同的是,它不能作为基类被继承。

 (3)union不能拥有静态数据成员或引用成员,因为静态数据成员实际上并不是共用体的数据成员,它无法和共用体的其它数据成员共享空间。对于引用变量,引用本质上是一个指针常量,它的值一旦初始化就不允许修改。如果共用体有引用成员,那么共用体对象一创建初始化后就无法修改,只能作为一个普通的引用使用,这就失去了共用体存在的意义。

 (4)union允许其他类的对象成为自己的数据成员,但是要求该类对象所属类不能定义constructor,copy constructor,destructor,assignment operator,virtual function中的任意一个。因为:
  (4.1)union数据成员共享内存,union构造函数在执行的时候,不能调用数据成员为类对象的构造函数,否则就改变了其他数据成员的值。
  (4.2)同样,union的对象成员的析构函数也不能被调用,因为其他数据成员的值对于对象成员而言可能毫无意义。
  (4.3)union的对象成员的赋值应该维持其原始语义,不建议进行赋值运算符的重载,因为赋值运算符重载一般用于“深拷贝”等场合,而在对象空间与其它变量共享的情况下,“深拷贝”引入的内存资源,指向内存资源的指针往往会被其它共用体数据成员修改,导致内存资源无法寻址,造成内存泄漏。此外,因为union的对象成员没有自定义的析构函数,也会导致内存泄漏。
  (4.4)拥有虚函数的类对象,虚函数表指针可能会在共用体对象初始化时被覆盖,导致无法寻址虚函数表,所以也不能拥有虚函数。

 (5)如果union类型旨在定义该类的同时使用一次,以后不再使用了,那么也可以不给出union的名称。如上例中变量u就是这种情况,这种情况下,无法为该union定义构造函数。

 (6)匿名共用体(Anonymous Union),也就是给出一个不带名称的共用体的申明后,并不定义任何该union的变量,而是直接以分号结尾。严格来说,匿名共用体并不是一种数据结构,因为它不能用来定义共用体对象,它只是指明若干个变量共享一片内存单元。在上例中,对变量p的修改实际上修改了变量q。可以看出,尽管匿名共用体中的变量被定义在同一个共用体中,他们与同一个程序块的任何其他局部变量具有相同的作用域级别。这意味着匿名共用体内的成员的名称不能与同一个作用域内的其它标识符相冲突。另外,对匿名共用体还存在如下限制:
   (6.1)匿名共用体不允许有成员函数;
   (6.2)匿名共用体也不能包含私有或者保护成员;
   (6.3)全局匿名共用体中的成员必须是全局或静态变量。

以上就是深入了解C++ 结构体(struct)与共用体(union)的详细内容,更多关于C++ 结构体与共用体的资料请关注脚本之家其它相关文章!

相关文章

  • c语言实现通讯录管理系统详细实例

    c语言实现通讯录管理系统详细实例

    这篇文章主要给大家介绍了关于c语言实现通讯录管理系统的相关资料,通讯录管理系统是一种常见的应用程序,可以用来管理联系人的信息,包括姓名、电话号码、地址等,需要的朋友可以参考下
    2023-07-07
  • 字典树的基本知识及使用C语言的相关实现

    字典树的基本知识及使用C语言的相关实现

    这篇文章主要介绍了字典树的基本知识及使用C语言的相关实现,这也是ACM等计算机考试和竞赛题目的基本知识,需要的朋友可以参考下
    2015-08-08
  • 详解C语言中accept()函数和shutdown()函数的使用

    详解C语言中accept()函数和shutdown()函数的使用

    这篇文章主要介绍了详解C语言中accept()函数和shutdown()函数的使用,用来操作socket相关的网络通信,需要的朋友可以参考下
    2015-09-09
  • C++ 项目引入lib和dll的区别与使用实战

    C++ 项目引入lib和dll的区别与使用实战

    静态链接库与动态链接库都是共享代码的方式,本文主要介绍了C++项目引入lib和dll的区别与使用实战,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • C++基于Directx MMX实现的图像灰度转换代码

    C++基于Directx MMX实现的图像灰度转换代码

    这篇文章主要介绍了C++基于Directx MMX实现的图像灰度转换代码,需要的朋友可以参考下
    2014-08-08
  • Dijkstra算法最短路径的C++实现与输出路径

    Dijkstra算法最短路径的C++实现与输出路径

    今天小编就为大家分享一篇关于Dijkstra算法最短路径的C++实现与输出路径,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • C++之预处理功能详解

    C++之预处理功能详解

    预处理器是 C++ 编译器提供的一个工具,允许程序员在编译之前对源代码文件做出修改,本文将给大家通过代码示例详细介绍C++的预处理功能,需要的朋友可以参考下
    2023-05-05
  • C++使用MFC获取PC硬件配置信息

    C++使用MFC获取PC硬件配置信息

    这篇文章主要为大家详细介绍了C++使用MFC获取PC硬件配置信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • C++ 动态内存分配详解(new/new[]和delete/delete[])

    C++ 动态内存分配详解(new/new[]和delete/delete[])

    这篇文章主要介绍了C++ 动态内存分配详解(new/new[]和delete/delete[]),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • 一文带你学会C语言中的qsort函数

    一文带你学会C语言中的qsort函数

    qsort函数是C语言的库函数,能实现对各种元素类型的比较,使用的基本思想是快速排序法,头文件是<stdlib.h>,本文不讲解具体实现原理,只对使用方法进行说明,希望对大家有所帮助
    2022-12-12

最新评论