• 友元类和友元函数


    友元类和友元函数

    一.友元函数

    问题:现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

    class Date
    {
    public:
    	Date(int year, int month, int day)
    		: _year(year)
    		, _month(month)
    		, _day(day)
    	{}
    	
    	ostream& operator<<(ostream& _cout)
    	{
    		_cout << _year << "-" << _month << "-" << _day << endl;
    		return _cout;
    	}
    //这实际上是 d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
    // 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
    	
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    友元函数可以直接访问类的私有成员,但它不是类的成员函数,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字,它可以在类定义的任何地方声明,不受类访问限定符限制。

    一个函数可以是多个类的友元函数,友元函数不能用const修饰,因为const指针修饰的是this所指向的对象,但是友元函数没有隐藏的this指针

    class Date
    {
    	friend ostream& operator<<(ostream& _cout, const Date& d);
    	friend istream& operator>>(istream& _cin, Date& d);
    public:
    	Date(int year = 1900, int month = 1, int day = 1)
    		: _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;
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    二.友元类

    ==友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

    友元关系是单向的,不具有交换性。

    比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time
    类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

    友元关系不能传递。

    如果B是A的友元,C是B的友元,则不能说明C时A的友元。

    友元关系不能继承。

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    内部类:
    如果一个类定义在另一个类的内部,那么这个类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。内部类可以定义在外部类的public、protected、private都是可以的。注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

    sizeof(外部类)=外部类的大小,和内部类没有任何关系。同时算一个类的大小与其中的静态成员变量也没有任何关系,因为我们计算一个类的大小,本质上是计算该类所定义对象的大小,但是静态变量存并不是存储在类中,而是存储在静态区中的,所以对象大小不包括静态成员变量的大小,那么类的大小也就不包括静态成员变量的大小。

    内部类实际上就是外部类的友元类(但是外部类不是内部类的友元),内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

    内部类受访问限定符的限制。

    class A {
    private:
    	static int k;
    	int h;
    public:
    	class B // B天生就是A的友元
    	{
    	public:
    		void foo(const A& a)
    		{
    			cout << k << endl;//OK
    			cout << a.h << endl;//OK
    		}
    	};
    };
    
    int A::k = 1;
    
    int main()
    {
    	A::B b;
    	b.foo(A());
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    vue3中表格单选
    Table of Laplace Transforms
    负载均衡下webshell连接nginx解析漏洞、sql注入第一关
    springboot基于微信小程序的电器商城系统的设计与实现毕业设计源码251453
    从CNN到Transformer:基于PyTorch的遥感影像、无人机影像的地物分类、目标检测、语义分割和点云分类
    商人宝:收银系统一般多少钱
    Tcache Stashing Unlink Attack 原理详解
    Vue 3 学习 源码解读
    关于archlinux的使用
    一对一关系实现部门和员工的查询
  • 原文地址:https://blog.csdn.net/weixin_44049823/article/details/126206678