「C++ 类和对象篇 13」友元和内部类

本文详细解释了C++中的友元概念,包括友元的定义、为何需要以及如何使用。重点讨论了友元在运算符重载和内部类中的应用,同时强调了友元可能带来的封装性降低和设计注意事项。
摘要由CSDN通过智能技术生成

目录

一、友元是什么?

二、为什么需要友元?

三、怎么使用友元?

四、友元的特性

五、内部类

1. 内部类是什么?

2. 内部类的作用

3. 定义内部类

4. 特性

【总结】


一、友元是什么?

        在C++中,友元(friend)是一种特殊的关系,通过将类A或函数A声明为类B的友元,它允许类A或函数A突破封装访问B类的私有成员。

        所以友元是一种定义在类外部的普通函数(友元函数)或类(友元类),为了与该类的成员函数加以区别,它需要在类体内加以关键字friend进行说明。友元不是类的成员,但是它可以访问类中的私有成员。


二、为什么需要友元?

        友元提供了一种突破封装的方式,让我们在没有访问器和修改器时也能对类的访问和修改,有时提供了便利。

        如运算符重载,运算符重载通常是全局函数,而不是类的成员函数。因此,这些全局函数通常无法直接访问类的私有成员。在类中将该全局函数声明为类的友元,我们可以让它访问类的私有成员,从而实现正确的操作符重载。


以重载<<和>>运算符为例:

如果我们在类中重载<<和>>,使用起来会非常怪异:

因为在成员函数的第一个参数为隐藏的this指针,istream类的对象cin(ostream类的对象cout)则成为了第二个参数,所以使用时对象d在前,对象cin和cout在后。


想要正常使用需将>>和<<在全局域重载,这时我们要声明友元:

#include<iostream>
using std::cin; using std::cout; using std::endl; 
using std::istream; using std::ostream;

class Date
{
    //声明友元
	friend istream& operator>> (istream& _cin, Date& d);
	friend ostream& operator<< (ostream& _cout, Date& d);
private:
	int _year;
	int _month;
	int _day;
public:
	Date(int y = 2024, int m = 1, int d = 1)
		:_year(2024),_month(1),_day(1)
	{
		_year = y, _month = m, _day = d;
	}
};

//重载写在需要的类的后面,不然找不到该类
//cin为标准库中istream类的对象,cout为ostream类的对象
istream& operator>> (istream& _cin, Date& d){
	_cin >> d._year >> d._month >> d._day;
	return _cin;//有返回值才支持连续赋值
}

ostream& operator<< (ostream& _cout, Date& d){
	_cout << "当前日期为:" << d._year << "年" << d._month << "月" << d._day << "日\n";
	return _cout;
}

int main(){
	Date d;
	cout << "请输入年月日(使用空格分隔):";
	cin >> d;
	cout << d;
	return 0;
}


        之所以能直接使用对象cout和cin输入输出所有内置类型,是因为在标准库中已经将它们的类的<<和>>都重载好了,<<和>>能够自动识别类型,是因为它们之间构成了函数重载。如果需要定制一个类的输入输出,在全局域重载<<和>>即可。


三、怎么使用友元?

        在C++中使用关键字friend来声明友元关系。声明友元函数是friend加函数声明,声明友元类则是friend加class加类名:

        当一个类或函数被声明为另一个类的友元时,它在外部也能够访问该类的私有成员。

        友元会增加耦合度,破坏封装,可能会导致代码的可维护性和可读性降低,所以友元不宜多用。 


四、友元的特性

  • 一个函数可以是多个类的友元。
  • 友元函数可访问类的私有和保护成员,但不是类的成员函数。
  • 友元函数可以在类中的任何地方声明,不受类访问限定符限制。
  • 友元函数不能用const修饰,编译器不会给友元函数传递this指针,因为友元函数不是类的成员函数
  • 友元关系不能传递。(如果B是A的友元,CB的友元,则不能说明C是A的友元。)
  • 友元类中的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
  • 友元是单向的,不具有交换性。(比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。)
  • 友元关系不能继承。

五、内部类

1. 内部类是什么?

        内部类和外部类是相对的,如果类A定义在类B的内部,那么类A就是类B的内部类,类B是类A的外部类。

2. 内部类的作用

        与友元类相比,内部类的存在可以提供更好的封装性和代码组织性。它允许外部类和内部类之间共享数据和方法,同时保持了较高的封装性。内部类可以访问外部类的私有成员,这使得内部类可以更方便地访问和操作外部类的数据。

3. 定义内部类

class A{
private:
	int a;
public:
	class B // B天生就是A的友元
    {
	private:
		int b;
	};
};

4. 特性

  • 内部类就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
  • 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名,因为内部类也是外部类的成员。
  • 内部类中默认没有外部类的对象,无法访问外部类中非static成员(编译器不会像成员函数那样给内部类传递this指针)。所以内部类的成员函数如果要访问外部类中的非静态成员,需要给该成员函数传递一个外部类的对象作为参数。当然外部类要访问内部类的非静态public成员也需要一个内部类的对象。

  • sizeof(外部类)=外部类,外部类的大小和内部类没有任何关系。

【总结】


------------------------END-------------------------

才疏学浅,谬误难免,欢迎各位批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烛火萤辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值