心之所向
素履以往
目录
契子✨
我们之前已经把类与对象的基础知识已经学完了,这些是只针对一个类的操作
那么两个类甚至多个类之间能不能有联系呢?
比如 日期类Date 想要访问 时间类Time ,配合的输出当下的具体时间
答案当然是可行的,这就要借助我们的友元来解决问题
友元的简介(百度百科):
友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以 关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。
友元函数
先举个小栗子~
cout 如何输出自定义类型✨
因为我们最近写的都是自定义类型 -- class,所以想用 cout 输出自定义类型的数据就用不了了
如果我们仍想用 cout 输出数据则需要符号重载 <<
#include<iostream>
#include<cstdlib>
using namespace std;
class Date
{
public:
Date()
: _year(2024)
, _month(4)
, _day(19)
{}
ostream & operator<<(ostream& _cout)
{
cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 ";
return _cout;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1<< cout<<endl;
system("pause");
return 0;
}
d1<< cout 等价于 d1.operator<<(&d1, cout)
现在尝试去重载 operator<< ,然后发现没办法将 operator<< 重载成成员函数。因为 cout 的输出流对象和隐含的 this 指针在抢占第一个参数的位置。this 指针默认是第一个参数也就是左操作数了。
总觉得这种写法很别扭,有没有办法变成 cout<< d1 呢?
实际使用中 cout 需要是第一个形参对象才能正常使用,也就是 cout.operator<<(cout, &d1)
所以要将 operator<< 重载成全局函数即可
但又会导致类外没办法访问成员,此时就需要友元函数来解决
✨friend 加以修饰的函数便是友元函数,也就是说在这个函数中可以访问到类的成员
~就好比与我是你的好兄弟,我可以用你的东西
#include<iostream>
#include<cstdlib>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& _cout, const Date& d);
public:
Date()
:_year(2024)
, _month(4)
, _day(19)
{}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
cout << d._year << " 年 " << d._month << " 月 " << d._day << " 日 ";
return _cout;
}
int main()
{
Date d1;
cout << d1 << endl;
system("pause");
return 0;
}
友元函数 可以 直接访问 类的 私有 成员,它是 定义在类外部 的 普通函数 ,不属于任何类,但需要在类的内部声明,声明时需要加 friend 关键字
既然输出都写了,那我们在写一个输入吧
cin 如何输入自定义类型✨
#include<iostream>
#include<cstdlib>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& _cout, const Date& d);
friend istream& operator>>(istream& _cin, Date& d);
public:
Date(int year = 2024,int month = 4,int day = 19)
:_year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
cout << d._year << " 年 " << d._month << " 月 " << d._day << " 日 ";
return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{
_cin >> d._year;
_cin >> d._month;
_cin >> d._day;
return _cin;
}
int main()
{
Date d;
cin >> d;
cout << d << endl;
system("pause");
return 0;
}
总结
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元函数可访问类的私有和保护成员,但不是类的成员函数 |
友元函数不能用const修饰 |
友元函数可以在类定义的任何地方声明,不受类访问限定符限制 |
一个函数可以是多个类的友元函数 |
友元函数的调用与普通函数的调用原理相同 |
友元类
先举个小栗子~
日期类Date 如何访问 时间类Time✨
#include<iostream>
#include<cstdlib>
using namespace std;
class Time
{
friend class Date;
public:
Time()
:_hour(6)
,_minute(3)
,_second(0)
{}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
public:
Date(int hour = 6, int minute = 30, int second = 6)
:_year(2024)
,_month(4)
,_day(19)
{
_t._hour = hour;
_t._minute = minute;
_t._second = second;
}
void Print()
{
cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 " << endl;
cout << this->_t._hour << " 时 " << this->_t._minute << " 分 " << this->_t._second << " 秒 " << endl;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
int main()
{
Date d1(6, 30, 48);
d1.Print();
system("pause");
return 0;
}
以上我在 Time 类中声明了 Date 类的友元
说明 Time 已经把 Date 当成了友人,Date 想用 Time 的东西(成员)顺便用即可~
这样老铁可能会有一个疑问?
那么 Time 可以访问 Date 的成员吗
以下代码是否正确呢?
class Time
{
friend class Date;
public:
Time(int year = 2024,int month =4,int day = 19)
:_hour(6)
,_minute(3)
,_second(0)
{
_d._year = year;
_d._month = month;
_d._day = day;
}
private:
int _hour;
int _minute;
int _second;
Date _d;
};
答案当然是 -- 否
你把我当兄弟,我用你的东西;但是我不把你当兄弟,我的东西你别想用
友元关系是单向的,不具有交换性 |
比如上述 Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接
那么友元可以传递吗?
比如 A 和 B 是朋友,B 和 C 是朋友,那么 A 和 C 会成为朋友吗
这里举个小栗子~ 以下代码是否正确呢?
#include<iostream>
#include<cstdlib>
using namespace std;
class A
{
friend B;
public:
A()
:_a(0)
{
_cc._c = 0;
}
private:
int _a;
C _cc;
};
class B
{
friend C;
private:
int _b;
};
class C
{
private:
int _c;
};
class C
{
friend A;
private:
int _c;
};
小总结
友元关系不能传递
|
内部类
概念:
如果一个类定义在另一个类的内部,这个内部类就叫做内部类 。内部类是一个独立的类, 它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。注意: 内部类就是外部类的友元类 ,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
简单来讲:外部类就是内部类(女神)的舔狗,女神想对舔狗做什么,舔狗都得接受;而舔狗想要的连一点温馨的问候都没有,舔狗是没有尊严的,外部类也是如此~
#include<iostream>
#include<cstdlib>
using namespace std;
class A
{
public:
class B
{
public:
void Print(const A&a)
{
cout << a._a << endl;
}
private:
int _b;
};
private:
int _a = 10;
};
int main()
{
A::B b;
b.Print(A());
system("pause");
return 0;
}
其实 B (内部类)是个独立的类,只是放在 A (外部类)里面仅仅受到类域的限制
比如在声明对象的时候还要先写外部域 (A::B)
其次 B 拥有 A 的所有特权,但是 A 没有 B 的一点特权
(B天生就是A的友元,内部类可以访问外部类的私有)
外部类A 却访问不到 内部类B
那么 A 不想当舔狗怎么办呢?
我们可以把内部类设置为私有,这样就不能被外界访问了
class A
{
private:
class B
{
public:
void Print(const A&a)
{
cout << a._a << endl;
}
private:
int _b;
};
private:
int _a = 10;
};
可能有老铁会问,两个类嵌套的大小是多少呢?
#include<iostream>
#include<cstdlib>
using namespace std;
class A
{
private:
static int k;
int h;
public:
class B
{
public:
void foo(const A& a)
{
cout << k << endl;
cout << a.h << endl;
}
private:
int _b;
};
};
int A::k = 1;
int main()
{
cout << sizeof(A) << endl;
system("pause");
return 0;
}
我们来计算一下~
我们发现 sizeof 计算的是外部类,和内部类没有任何关系
void foo(const A& a)
{
cout << k << endl;
}
注意:内部类可以直接访问外部类中的 static 成员,不需要外部类的对象
总结:
内部类可以定义在外部类的public、protected、private都是可以的 |
注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名 |
sizeof计算的是外部类,和内部类没有任何关系 |
先介绍到这里啦~
有不对的地方请指出💞