主题:C++ 细碎知识杂讲
主讲:Menou
参考书籍:《C++从入门到入土》
内容:
1、结构体(struct)和共用体(union)我们学习过结构体,结构体可以理解成一个广义的,加强版的数组,结构体较于数组的优势是可以将多样的信息存放在一个相邻的,有意义的内存(域?)内。而数组只能存放单一类型的信息。
而共用体是使用覆盖技术,允许不同类型的变量存放到同一段内存单元内,几个变量互相覆盖的一种数据类型。
union 共用体名 { 成员列表 };
我们通过这种方式定义共用体。共用体名可以省略。
定义共用体的方式和结构体一样有三种,他们都是等效的。
如何输出共用体成员变量?我们写个简单的程序,顺便验证一下共用体的特性。
#include#include using namespace std; int main(){ union Mydata{ int i; float f; char str[50]; }datel; datel.i=56; datel.f=150.33; strcpy(datel.str,"Beautiful World"); cout<<"datel.i=="< 输出结果:
/Users/Menou/untitled12/cmake-build-debug-/untitled12 datel.i==1969317186 datel.f==2.85723e+32 datel.str==Beautiful World 进程已结束,退出代码为 0对照上述代码,发现 i 和 f 值都是垃圾数据,证明 i 和 f 被“覆写”了。
既然如此,我们不妨改进一下程序:
#include#include using namespace std; int main(){ union Mydata{ int i; float f; char str[50]; }datel; datel.i=56; cout<<"datel.i=="< 改进后,结果果真是正常的
/Users/Menou/untitled12/cmake-build-debug-/untitled12 datel.i==56 datel.f==150.33 datel.str==Beautiful World 进程已结束,退出代码为 0顺便补充一个知识,关于用户自定义的数据类型typedef,在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。说完了介绍,下边说用法:1、最简单的,给已知变量起个新名字
typedef long byte_4;这个很容易理解
2、稍微复杂,与结构体结合
typedef struct tagMyStruct { int iNum; long lLength; }MyStruct;这一步实际上完成两个 *** 作:其一,定义一个新的结构类型 struct tagMyStruct;其二,typedef为这个新的结构起了一个名字,叫MyStruct。
MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。
在看CSDN文的时候发现一个没有注意到的有趣问题,就是
typedef struct tagNode { char* pItem; pNode* pNext; }pNode;但是IDE里边报错了,为什么?
报错的是第二个指针,错误原因是:Unknown type name 'pNode';不知道‘pNode’?但我在结构体最后不是定义了吗??我们接着往下看。
学过数据结构的同学知道,C++语言是允许在结构中包含指向它自己(结构)的指针,我们在链表的结点等见过很多这样的 *** 作。因此第二个指针看起来是合理的。
根据我们上面的阐述可以知道:新结构建立的过程中遇到了 pNext 域的声明,类型是 pNode ,但是,我们要知道,pNode 表示的是类型的新名字,在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候IDE根本不认识什么叫 pNode 。
如何解决?我们可以从链表的建立中得到思路,既然链表是分为链表表结构以及表中元素(结点)结构两部分来建立的(依据我们学校开设的课程,我们是用类来处理两个结构,即建立表类,以及结点类两个类):
struct tagNode { char* pItem;//不变 struct tagNode* pNext;//指向tagNode的指针, //这里的tagNode是被编译器所理解的,因此合法 }; typedef struct tagNode* pNode;//再利用typedef的功能,将这个指针“命名”为pNode再者,typedef可以和#define命令互换?这个就讲到这吧,到这就差不多了。
2、类(Class)的知识首先明确,类是一个数据结构,他包含对象的“属性”(是什么),和“ *** 作”(能干啥)。对象是类的实例(即具体的类)。
所谓面向对象,其实就是九个概念,类、类变量、数据成员、方法重写、实例变量、继承、实例化、方法、对象。
对于类的定义和类的访问修饰符(public、private、protected保护类)、类的构造/析构函数等请读者自查自学。
下边讲点零碎的,读者可能没有注意到的知识。
1、指向对象的指针为什么是指向对象的指针而不是指向类的指针?因为类只是种结构,而对象才是实实在在的数据,指针指而有物。
其二,在指向对象的指针成功赋值后,例如:
#include#include using namespace std; class Students{ public: char name[10];//name int No;//序号 int score;//score Students(){ cout<<"创建完成"< >p->name; cin>>p->No; cin>>p->score; cout< name< No< score< 结果:
/Users/yuwenao/untitled12/cmake-build-debug-/untitled12 创建完成 创建完成 Klee 13 299 Klee 13 299 解构完成 解构完成 进程已结束,退出代码为 0可见,指向对象的指针指向具体对象后可以用“->“来访问类元素。
2、友元函数和友元类我们知道,由于类对于信息的封装,我们通过对象仅可访问public成员,只有本类的函数可以访问类的 private 类型。而有一种特殊情况就是,借助友元(friend),可以使得其他类 中的成员函数以及全局范围的函数访问当前类的 private 成员和 protected 成员。
友元不是成员函数,但是它可以访问类中的私有成员。
友元函数:
#include#include using namespace std; class Students{ private: char name[10];//name int No;//序号 int score;//score public: Students(){ cout<<"创建完成"< >pp->name>>pp->No>>pp->score; } void OutPut(Students *pp) { //由此可以在不添加任何类头衔的情况下编写函数 cout<<"Name:"< name<<" No:"< No<<" score:"< score< 基于上边的程序稍微修改:
1、将学生姓名、学号、成绩等设为私有成员;
2、将创建对象、解析对象函数设为公有成员;
3、编写全新 的输入输出函数,并在类里边将两个 IO 函数设为友元函数。
查看结果
/Users/yuwenao/untitled12/cmake-build-debug-/untitled12 创建完成 //输入// Klee 13 278 //输出// Name:Klee No:13 score:278 解构完成 进程已结束,退出代码为 0此时两个友元函数不属于任何类,他是全局的。
友元类
这种情况下,整个类都是友元。若要声明函数为一个类的友元,需要在函数原型最前边加上 friend 关键字。如下:
#includeusing namespace std; class Address; class Students{ private: char name[10];//name int No;//序号 int score;//score public: Students(){ cout<<"创建完成"< >pp->name>>pp->No>>pp->score; } class Address{ private: char country[20]; char Working_Place[60]; public: void IIPut(){ cin>>country; cin>>Working_Place; } //讲Students声明为友元类 friend class Students; }; void Students::OutPut(Address *sp) { //由此可以在不添加任何类头衔的情况下编写函数 cout<<"Name:"< country<<" Working Place:"< Working_Place< IIPut(); cout<<"OUTPUT:"< OutPut(apl); return 0; } 淦,这段码改 bug 改了一个小时,吐了
/Users/yuwenao/untitled12/cmake-build-debug-/untitled12 创建完成 INPUT: Klee 9 297 Mondstadt Knights_of_the_XiFeng OUTPUT: Name:Klee No:9 score:297 County:Mondstadt Working Place:Knights_of_the_XiFeng 解构完成 进程已结束,退出代码为 0虽然这段程序有点不切换现实,怎么可能让辣么可爱的可莉去考试呢?但还是姑且写出来。
修改:1、将 Students 类的友函数 OutPut 删除,新增 Students 类新成员函数 OutPut。
2、新增类 Address,Students 类是 Address 类的友元类。
3、修改了 OutPut,利用友元类的特性在 Students 的成员函数中输出 Address 的成员数据。
由此,我们理解了友元类。
最后提醒:友元关系是单向的。即:Students 是 Address 的友元,但是 Address不是 Students 的友元。Students 是 Address 的友元意味着 Students 可以使用“朋友”的成员数据。反之则不然。
最后,因为友元关系的单向性,由此友元关系也不能传递。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)