24.友元函数

1.友元

  类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部(作用域之外)访问。但是,有时候需要在类的外部访问类的私有成员,怎么办?

  解决方法是使用友元函数,友元函数是一种特权函数,c++允许这个特权函数访问私有成员。这一点从现实生活中也可以很好的理解:

  比如你的家,有客厅,有你的卧室,那么你的客厅是Public的,所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是呢,你也可以允许你的闺蜜好基友进去。

  程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。

1.1.友元语法

● friend关键字只出现在声明处

●其他类、类成员函数、全局函数都可声明为友元

●友元函数不是类的成员,不带this指针

●友元函数可访问对象任意成员属性,包括私有属性

class Building;
//友元类
class MyFriend{
public:
	//友元成员函数
	void LookAtBedRoom(Building& building);
	void PlayInBedRoom(Building& building);
};
class Building{
	//全局函数做友元函数
	friend void CleanBedRoom(Building& building);
#if 0
	//成员函数做友元函数
	friend void MyFriend::LookAtBedRoom(Building& building);
	friend void MyFriend::PlayInBedRoom(Building& building);
#else	
	//友元类
	friend class MyFriend;
#endif
public:
	Building();
public:
	string mSittingRoom;
private:
	string mBedroom;
};

void MyFriend::LookAtBedRoom(Building& building){
	cout << "我的朋友参观" << building.mBedroom << endl;
}
void MyFriend::PlayInBedRoom(Building& building){
	cout << "我的朋友玩耍在" << building.mBedroom << endl;
}

//友元全局函数
void CleanBedRoom(Building& building){
	cout << "友元全局函数访问" << building.mBedroom << endl;
}

Building::Building(){
	this->mSittingRoom = "客厅";
	this->mBedroom = "卧室";
}

int main(){

	Building building;
	MyFriend myfriend;

	CleanBedRoom(building);
	myfriend.LookAtBedRoom(building);
	myfriend.PlayInBedRoom(building);

	system("pause");
	return EXIT_SUCCESS;
}

    [友元类注意]
1.友元关系不能被继承。
2.友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。
3.友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。

思考: c++是纯面向对象的吗?

如果一个类被声明为friend,意味着它不是这个类的成员函数,却可以修改这个类的私有成员,而且必须列在类的定义中,因此他是一个特权函数。c++不是完全的面向对象语言,而只是一个混合产品。增加friend关键字只是用来解决一些实际问题,这也说明这种语言是不纯的。毕竟c++设计的目的是为了实用性,而不是追求理想的抽象。
                                                                                                                                                                                                                                --- Thinking in C++


2.视频内容

程序1(全局函数的友元):

#pragma warning(disable:4996)
//2022年9月26日20:02:07
#include <iostream>
using namespace std;
#include <string>

class Building
{
    //声明这个全局函数为Building类的友元函数
    friend void GoodGay(Building &bd);
private:
    string woshi;
public:
    string keting;

public:
    Building()
    {
        keting = "客厅";
        woshi = "卧室";
    }
};
 
void GoodGay(Building& bd)
{
    cout << "好基友访问:" << bd.keting << endl;
    cout << "好基友访问:" << bd.woshi << endl;
}

void test01()
{
    Building my;

    GoodGay(my);
}

int main()
{
    test01();

    system("pause");
    return EXIT_SUCCESS;
}

输出结果:

好基友访问:客厅
好基友访问:卧室
请按任意键继续. . .

重点难点:

1	友元的作用:在类外访问类的私有成员
2	友元分:友元函数,友元类,成员函数的友元函数
3	在普通函数或类的前面加上friend,在类中声明
4	友元类不能被继续,友元是单向,友元没有传递性

程序2(友元类):

#pragma warning(disable:4996)
//2022年9月26日21:00:093
#include <iostream>
using namespace std;

class Building
{
    //声明GoodF类为友元类
    friend class GoodF;
public:
    string keting;
private:
    string woshi;

public:
    Building()
    {
        keting = "客厅";
        woshi = "卧室";
    }
};

class GoodF
{
public:
    void func(Building &bd)
    {
        cout << "访问: " << bd.keting << endl;
        cout << "访问: " << bd.woshi << endl;
    }
};
//1.通过传入参数来访问类的私有成员
void test01()
{
    Building bd;
    GoodF f;
    f.func(bd);
}

int main()
{
    test01();
    system("pause");
    return EXIT_SUCCESS;
}

输出结果:

访问: 客厅
访问: 卧室
请按任意键继续. . .

程序3:

#pragma warning(disable:4996)
//2022年9月26日21:00:093
#include <iostream>
using namespace std;

class Building
{
    //声明GoodF类Building类的友元类
    friend class GoodF;
    friend class GoodF2;
public:
    string keting;
private:
    string woshi;

public:
    Building()
    {
        keting = "客厅";
        woshi = "卧室";
    }
};
class GoodF
{
public:
    void func(Building &bd)
    {
        cout << "访问: " << bd.keting << endl;
        cout << "访问: " << bd.woshi << endl;
    }
};
//1.通过传入参数来访问类的私有成员
void test01()
{
    Building bd;
    GoodF f;
    f.func(bd);
}

//2.通过类内指针来访问类的私有成员
class GoodF2
{
public:
    Building *pbu;

public:
    GoodF2()
    {
        pbu = new Building;
    }
    void func()
    {
        cout << "访问: " << pbu->keting << endl;
        cout << "访问: " << pbu->woshi << endl;
    }
};
void test02()
{
    GoodF2 f;
    f.func();
}

int main()
{
    test02();
    system("pause");
    return EXIT_SUCCESS;
}

输出结果:

访问: 客厅
访问: 卧室
请按任意键继续. . .

程序4:

#pragma warning(disable:4996)
//2022年9月26日21:00:093
#include <iostream>
using namespace std;

class Building
{
    //声明GoodF类Building类的友元类
    friend class GoodF;
    friend class GoodF2;
public:
    string keting;
private:
    string woshi;

public:
    Building()
    {
        keting = "客厅";
        woshi = "卧室";
    }
};
class GoodF
{
public:
    void func(Building& bd)
    {
        cout << "访问: " << bd.keting << endl;
        cout << "访问: " << bd.woshi << endl;
    }
};
//1.通过传入参数来访问类的私有成员
void test01()
{
    Building bd;
    GoodF f;
    f.func(bd);
}

//2.通过类内指针来访问类的私有成员
class GoodF2
{
public:
    Building* pbu;

public:
    GoodF2()
    {
        cout << "无参构造" << endl;
        pbu = new Building;
    }
    void func()
    {
        cout << "访问: " << pbu->keting << endl;
        cout << "访问: " << pbu->woshi << endl;
    }
    //拷贝构造
    GoodF2(const GoodF2& f2)
    {
        cout << "拷贝构造" << endl;
        //1.申请空间
        pbu = new Building;
        ////2.拷贝数据
        //pbu->keting =
    }
    ~GoodF2()
    {
        cout << "析构函数" << endl;
        if (pbu != NULL)
        {
            delete pbu;
        }
    }
};
void test02()
{
    GoodF2 f;
    f.func();

    GoodF2 f2 = f;
}

int main()
{
    test02();
    system("pause");
    return EXIT_SUCCESS;
}

输出结果:

访问: 客厅
访问: 卧室
拷贝构造
析构函数
析构函数
请按任意键继续. . .

程序5:

#pragma warning(disable:4996)
//2022年9月30日18:37:34

#include <iostream>
using namespace std;

//1.编译器直到类的声明,不知道类的结构
class Building;//声明类
class GoodGay
{
public:
    void func(Building& bud);
};

class Building
{
    //声明GoodGay类的成员func()成为BUilding类的友元函数
    friend void GoodGay::func(Building &bud);
public:
    Building()
    {
        keting = "客厅";
        woshi = "卧室";
    }

public:
    string keting;
private:
    string woshi;
};

void GoodGay::func(Building& bud)
{
    cout << "访问:" << bud.keting << endl;
    cout << "访问:" << bud.woshi << endl;
}

void test()
{
    Building bud;
    GoodGay GF;
    GF.func(bud);
}

int main()
{
    test();
    system("pause");
    return EXIT_SUCCESS; 
}

输出结果:

访问:客厅
访问:卧室
请按任意键继续. . .
posted @ 2022-09-30 19:10  CodeMagicianT  阅读(67)  评论(0编辑  收藏  举报