1. 友元函数定义
友元函数是定义在类外部的普通函数,不属于任何类,但可以直接访问类的私有成员,需要在类的内部使用friend关键字进行声明,类就会把友元函数当作类里面的成员。
#include<iostream>
using namespace std;
class Date
{
//友元函数
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
//构造函数
Date(int year = 2022, int month = 4, int day = 8)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out,const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
return _cout;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year;
in >> d._month;
in >> d._day;
return in;
}
int main()
{
Date d1;
cin >> d1;
cout << d1 <<endl;
return 0;
}
1.1 友元函数的特性
(1)友元函数可访问类的私有和保护成员,但不是类的成员函数
(2)友元函数不能用const修饰(const修饰this指针指向的内容,友元函数作为全局函数没有this指针)
(3)友元函数可以在类定义的任何地方声明,不受类访问限定符限制
(4)一个函数可以是多个类的友元函数
(5)友元函数的调用与普通函数的调用和原理相同
2. 友元类
2.1 友元类的定义
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。如下Date类是Time类的友元类,Date类要访问Time类,就要把Date类定义成Time类的友元:
class Date; // 前置声明
class Time
{
friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:
Time(int hour = 0, int minute = 0, int second = 0)
: _hour(hour)
, _minute(minute)
, _second(second)
{}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
void SetTimeOfDate(int hour, int minute, int second)
{
// 直接访问时间类私有的成员变量
_t._hour = hour;
_t._minute = minute;
_t._second = second;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
int main()
{
return 0;
}
2.2 友元类的特性
(1)友元关系是单向的,不具有交换性。
在Time类中,声明Date 类是其友元类,可以在Date类中直接访问Time类的私有成员。但不能在Time中访问Date类中的私有成员。
(2)友元关系不能传递
A是B的友元,B是C的友元,但A不是C的友元。
3. 内部类
一个类定义在另一个类的内部,这个内部类就叫做内部类。
内部类和外部类关系:
(1)内部类不属于外部类,更不能通过外部类的对象调用内部类。外部类对内部类没有任何优越的访问权限。
(2)内部类是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类的所有成员,但外部类不是内部类的友元。
3.1 内部类的特性
(1)内部类可以定义在外部类的public、protected、private都是可以的。
(2)注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。
(3)sizeof(外部类)=外部类,和内部类没有任何关系
A无论是类还是全局函数,只要A被定义为B的友元,A就可以访问B的非公有成员。
4. 线性表的链式存储
4.1链表的定义
链式存储和顺序存储的不同在于顺序存储用的是连续的地址,但是链式存储是用一组任意的存储单元存储数据的,地址可以是连续的也可以是不连续的。
为了能表示(存储)元素之间的逻辑关系(线性),在存放每个元素的同时,也存放相关元素的信息(相关元素的存储地址),即用指针来表示元素之间的逻辑关系。
4.2 链表的实现
我们用两个类来实现对链表的定义以及操作,一个是链表节点类LinkNode,用来定义一些指针节点以及初始化和分配内存;另一个是链表类,用来定义一些对于链表的操作。(链表类是链表节点类的友元)
#include <iostream>
#include <stdio.h>
using namespace std;
typedef int T;
class LinkList;
class LinkNode
{
friend class LinkList;
private:
LinkNode *link;
T data;
public:
LinkNode(LinkNode *ptr=NULL)
{
link=ptr;
}
LinkNode(const T &item,LinkNode *ptr=NULL)
{
data=item;
link=ptr;
}
~LinkNode() {};
};
class LinkList
{
private:
LinkNode *first;
public:
LinkList();//构造函数
~LinkList();
int Length();//返回链表的长度
bool Insert(int i,T x);//向链表中插入元素
LinkNode *Locate(int i);//返回链表i出的节点值
void Input(T endTag);//按条件输入(顺序)
void Input2(T endTag);//按条件输入(逆序)
void PrintList();//打印链表
bool Delete(T &x);//删除值为x的节点
void Search(T &x);//按值查找
bool Find(T x);//查询链表中是否存在x
void Cross(LinkList &A,LinkList &B,LinkList &C);//链表的交操作
void Union(LinkList &A,LinkList &B);//链表的并操作
void Sort();//对链表进行排序
};
LinkList::LinkList()
{
first = new LinkNode;
first->data = 0;
first->link = NULL;
}
LinkNode *LinkList::Locate(int i)
{
LinkNode *p=first;
int j=0;
if(i<0)
{
return NULL;
}
while(p!=NULL&&j<i)
{
p=p->link;
j++;
}
return p;
}
LinkList::~LinkList()
{
delete first;
}
bool LinkList::Insert(int i,T x)
{
LinkNode *p=Locate(i-1);
if(p==NULL)
{
return false;
}
LinkNode *newNode=new LinkNode(x);
newNode->link=p->link;
p->link=newNode;
}
void LinkList::Input(T endTag)
{
LinkNode *newNode,*r;
T val;
cin>>val;
r=first;
while(val!=endTag)
{
newNode=new LinkNode(val);
r->link=newNode;
r=newNode;
cin>>val;
}
r->link=NULL;
}
void LinkList::Input2(T endTag)
{
LinkNode *newNode,*r;
T val;
cin>>val;
r=first;
while(val!=endTag)
{
newNode=new LinkNode(val);
newNode->link=r->link;
r->link=newNode;
cin>>val;
}
}
void LinkList::PrintList()
{
LinkNode *p=first->link;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->link;
}
cout<<endl;
}
bool LinkList::Delete(T &x)
{
LinkNode * p, *q = NULL;
p = first->link;
if (p == NULL)
{
return false;
}
while (p->data!=x&&p->link!=NULL)
{
q = p;
p = p->link;
}
if (p->data == x)
{
q->link = p->link;
delete p;
}
}
int LinkList::Length()
{
int i=0;
LinkNode *p=first->link;
while(p!=NULL)
{
i++;
p=p->link;
}
return i;
}
void LinkList::Search(T &x)
{
LinkNode *p=first->link;
int count=1,flag=0;
while(p!=NULL)
{
if(p->data==x)
{
flag=1;
break;
}
count++;
p=p->link;
}
if(flag)
{
cout<<x<<" is located at index of "<<count<<endl;
}
else
{
cout<<x<<" is not found"<<endl;
}
}
bool LinkList::Find(T x)
{
LinkNode *p=first;
while(p!=NULL)
{
if(p->data==x)
{
return true;
}
p=p->link;
}
return false;
}
void LinkList::Cross(LinkList &A,LinkList &B,LinkList &C)
{
T t;
for(int i=1; i<=B.Length(); i++)
{
t=B.Locate(i)->data;
if(A.Find(t))
{
C.Insert(C.Length()+1,t);
}
}
}
void LinkList::Union(LinkList &A,LinkList &B)
{
T t;
for(int i=1; i<=B.Length(); i++)
{
t=B.Locate(i)->data;
if(!A.Find(t))
{
A.Insert(A.Length()+1,t);
}
}
}
void LinkList::Sort()
{
LinkNode *p=first,*q=NULL;
while(p!=q)
{
while(p->link!=q)
{
if(p->data>p->link->data)
{
int t=p->data;
p->data=p->link->data;
p->link->data=t;
}
p=p->link;
}
q=p;
p=first;
}
}
int main()
{
int n,m,t=0,a[10000],x1,y1,x2,x3,x4;
cin>>n;
LinkList p,q,r;
p.Input(n);
cout<<"A is created as: ";
p.PrintList();
cin>>x1>>y1;
p.Insert(x1,y1);
cout<<"After inserted A is ";
p.PrintList();
cin>>x2;
p.Delete(x2);
cout<<"After deleted A is ";
p.PrintList();
cin>>x3;
p.Search(x3);
cin>>x4;
p.Search(x4);
cin>>m;
q.Input(m);
cout<<"B is created as: ";
q.PrintList();
p.Cross(p,q,r);
cout<<"A cross B is ";
r.PrintList();
p.Union(p,q);
cout<<"A union B is ";
p.PrintList();
p.Sort();
cout<<"A union B in sequence is ";
p.PrintList();
return 0;
}