类与对象
- 1 友元
- 1.1 概念:
- 1.2 友元函数
- 1.3 友元类
- 2 内部类
- 概念:
- 特性:
- 举例:
- 3 匿名对象
- Thanks♪(・ω・)ノ谢谢阅读!!!
- 下一篇文章见!!!
1 友元
1.1 概念:
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不易多用
友元分为:友元函数 和 友元类。
友元关键字 :friend 可以理解为我把他看做朋友,所以他可以使用我的东西。这就是友元做到的事情是类似的,通过设置友元,在一个类中可以访问类外的函数与变量。
1.2 友元函数
我们现在来实现日期类Date的流输出<<重载,那么我们来看:
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//这里 参数有两个 (Date* this , ostream& out )
//左右操作数不一致。
ostream& operator<<(ostream& out) {
out << _year << '-' << _month << '-' << _day << endl;
return out;
}
private:
int _year;
int _month;
int _day;
};
int main(){
Date a1(2024,2,24);
cout << a1;
return 0;
}
这样必然会出现问题,因为在成员函数中第一个参数默认为(Date* this)所以在使用<<时就会出现参数不匹配环节。
所以要想改变默认参数的顺序,就要把operator<<重载为全局函数,但是这样无法访问Date的私有变量,此时就可以通过友元来解决这个问题。来看修改后的代码
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
friend ostream& operator<<(ostream& out, Date& d);
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, Date& d) {
out << d._year << '-' << d._month << '-' << d._day << endl;
return out;
}
int main() {
Date a1(2024, 2, 24);
cout << a1;
return 0;
}
现在就可以顺利的使用<<重载了。
总结一下:
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在
类的内部声明,声明时需要加friend关键字。
友元声明只能出现在类定义的内部,但是类内出现的具体位置不限。友元不是类的成员也不受它所在区域访问控制级别的约束。一般来说,最好在类定义开始或结束区域集中声明友元。
注意:
- 友元函数可访问类的私有和保护成员,但不是类的成员函数
- 友元函数不能用const修饰
- 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
- 一个函数可以是多个类的友元函数
- 友元函数的调用与普通函数的调用原理相同
1.3 友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类的非公用成员。
- 友元关系是单向的,不具有交换性(注意A类中声明友元B类,那么B类可以访问A类,但是A类不能访问B类),类似小明说小刚是他的朋友,但是小刚不一定把小明当做朋友。
- 友元关系不能传递(如果C类是B类的友元,B类是A类的友元,不能说明C类是A类的友元)
- 友元关系不能继承。
下面给出时间类Time 与 日期类Date 的示例,来帮助我们更好理解友元。
Time类中声明友元即可成功:
class Time
{
// 声明日期类为时间类的友元类,
//则在日期类中就直接访问Time类中的私有成员变量
friend class Date;
public:
Time(int hour = 0, int minute = 0, int second = 0)
: _hour(hour)
, _minute(minute)
, _second(second)
{}
private:
int _hour;
int _minute;
int _second;
};
2 内部类
概念:
如果一个类定义在另一个类的内部,这个内部类就叫做内部类。
内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
特性:
注意: 内部类就是外部类友元类,内部类可以通过外部类的对象参数来访问外部类的所有成员,但是外部类不是内部类的友元。
- 内部类可以定义在外部类的public、protected、private都是可以的。
- 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
- sizeof(外部类)=外部类,和内部类没有任何关系。
举例:
可以把友元实现的打印日期形成内部类,也可以做到相同效果。
#include<cstdio>
#include<iostream>
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;
}
定义内部类
class Time
{
friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类
中的私有成员变量
public:
Time(int hour = 0, int minute = 0, int second = 0)
: _hour(hour)
, _minute(minute)
, _second(second)
{}
void show(Date& d){
printf("时间是 %d年%d月%d日%d时%d分%d秒", d._year, d._month, d._day,
_hour,_minute,_second);
}
private:
int _hour;
int _minute;
int _second;
};
private:
int _year;
int _month;
int _day;
Time _t;
};
int main() {
Date d1(2024, 2, 26);
Date::Time t1(11, 26, 30);
t1.show(d1);
}
来看效果:非常好!!!
3 匿名对象
匿名对象可以帮助我们优化语句:
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
class Solution {
public:
int Sum_Solution(int n) {
//...
return n;
}
};
int main()
{
A aa1;
// 不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义
//A aa1();
// 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,
// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数
A();
A aa2(2);
// 匿名对象在这样场景下就很好用,当然还有一些其他使用场景,这个我们以后遇到了再说
Solution().Sum_Solution(10);
return 0;
}