友元 / 内部类 / 匿名对象

友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以
友元不宜多用

友元分为友元函数友元类

友元函数

什么是友元函数:类的友元函数是定义在类外部的普通函数,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字
在前面的写运算符重载的时候写到流运算符,重载有无法访问私有的问题。使用友元函数就可以解决此问题。

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. 友元函数不能用const修饰(指不能卸载函数后面,因为只要成员函数才能那样写,那样写是修改this指针的,但是可以写在前面,这样是修饰返回值的)
  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  4. 一个函数可以是多个类的友元函数
  5. 友元函数的调用与普通函数的调用原理相同

友元类

类似地,像一个友元函数一样,一个类也可以使用关键字friend成为另一个类的友元类。例如:

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;
};

注意,在Time的友元类Date中定义了Time _t;才可以访问,不能直接指定某个域直接访问,要定义出来才行。例如Date要访问Time中的某个成员变量,但是没有定义对象,那就无处去访问。加入要访问成员函数,但是我们编译器不知道成员函数中是否改变了成员变量,所以无法让其访问。必须要在Date中将Time实例化了才可以访问Time的成员。

  1. 友元关系是单向的,不具有交换性。
    比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接
    访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  2. 友元关系不能传递。
    如果C是B的友元, B是A的友元,则不能说明C时A的友元。
  3. 友元关系不能继承,在继承位置再详细介绍。

内部类

概念: 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。 内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越
的访问权限。

注意: 内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

特性1:外部类与内部类不存在包含关系

class A
{
public:
    class B
    {
    public:
	    void test()
        {

        }
    private:
        int _b;
    };
private:
    int _a;
};

int main()
{
    cout << sizeof(A) << endl;
    return 0;
}

内部类很容易被理解为外部的类的大小计算时要包含内部类的大小,其实并不是,不存在任何的包含关系,如下是执行结果。在这里插入图片描述

特性2:内部类与外部类的关系是内部类受到外部类的访问限制,这点与静态有点类似。内部类是全局的,只是访问的时候受到了类域的限制。

int main()
{
    cout << sizeof(A) << endl;
    A aa;
    A::B bb;
    bb.test();//当定义出来以后就可以访问了。
    return 0;
}

如上述,bb在定义的时候要受到类域和访问限定符的限制。要通过A来定义bb对象。

如果定义为私有的内部类,上述的写法就会报错了。在外部是无法访问的。
在这里插入图片描述
此时只能在外部类的里面创建内部类的对象。

class A
{
public:
    void creat()
    {
        B bb;
    }
private:
    class B
    {
    private:
        int _b;
    };
private:
	B bbb//如果不在函数内部,那么前面要声明了才能创建
    int _a;
};

int main()
{
    cout << sizeof(A) << endl;
    A aa;
   // A::B bb;
    return 0;
}

特性3:内部类可以访问外部类的私有和公有,但是外部类只可以访问内部类的公有,但是不能访问内部类的私有。即内部类天生是外部类的友元。

class A
{
public:
    void creat(int i)
    {
        B bb;
        bb.func2(i);//外部类通过调用内部类的公有函数改变内部类的值
    }
    //B bbb//不能直接创建,只能在函数里面创建
private:
    class B
    {
    public:
        void func1(A* pa)
        {
            pa->_a++;//内部类直接访问外部类的私有
        }
        void func2(int i)
        {
            _b += i;
        }
    private:
        int _b;
    };
private:
    int _a;
};

int main()
{
    cout << sizeof(A) << endl;
    A aa;
    return 0;
}

内部类和友元函数并不经常用,且两者都破坏了代码的独立性,所以不需要了解特别深。

匿名对象

匿名对象就是没有名字的对象,最大的特点就是声明周期只在定义的那一行
在这里插入图片描述
匿名对象会经常使用,使用场景如下是一种情况

class Date
{
public:
    void func()
    {
        cout << "test" << endl;
    }
private:
    int date;
};

int main()
{
    Date().func();
    return 0;
}

如上,只为了执行Date里面的func1()函数。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值