前言
"打牢基础,万事不愁" .C++的基础语法的学习."学以致用,边学边用",编程是实践性很强的技术,在运用中理解,总结.
以<C++ Prime Plus> 6th Edition(以下称"本书")的内容开展学习
引入
友元提供了一种特别的方式,访问对象私有数据.
友元有三种方式:友元非成员函数;友元类;友元成员函数;
从私有数据的访问说起
举例:建立一个Person类,声明年龄和姓名属性
main.h
#include<iostream>
using namespace std;
class Person {
string name;
int age;
public:
Person(const string& str,int ag):name(str),age(ag){}
int getAge() const{ return age; }
string getName() const{ return name; }
};
main.cpp //测试代码
#include<iostream>
#include"main.h"
int main(void) {
Person xiaozhang("小张", 35);
cout << "小张的年龄是:" << xiaozhang.getAge() << endl; //通过公开的接口访问私有数据
// cout << "小张的年龄是:" << xiaozhang.age << endl; //无法访问私有数据
}
----根据"数据私有,接口公开"这个编码原则,访问对象属性必须通过public中的接口函数
友元的各种实现
1.友元非成员函数
在public中定义一个打印对象信息的函数
经典代码(在本书P394)一是使用了友元访问私有数据,二是链式调用,不影响原有的cout
注:所谓经典代码,可以背下来的代码
friend ostream & operator<<(ostream& os, Person person) { //友元非成员函数定义
//可以使用erson.name和person.age了
os << "姓名为:" << person.name << "年龄为:" << person.age << endl;
return os; //返回引用,链式调用
}
说明:可以在同Person类的文件中定义,这里为了方便写成了内联函数.
测试代码,在main.cpp中添加
cout << xiaozhang; //调用友元函数
和接口函数的区别:用"对象.属性"取得属性值,而不是调用上面的接口函数"对象.getAge()",看起来更形象.
2.友元类
在Person类中声明友元类
friend class Friend; //友元类
编写友元类
这里用了两种方式:一是传入友元类对象引用,二是友元类对象依赖(也就是把对象作形参传入)
class Friend { //Person的友元类Friend
Person& person;
public:
Friend(Person& pe):person(pe){}
//传入对象引用,对象.属性访问
void print() {
cout <<"朋友姓名是:"<< person.name<<"," << "年龄是:" << person.age << endl;
}
//添加依赖,对象.属性访问
void print2(Person& person2){
cout << "朋友姓名是:" << person2.name << "," << "年龄是:" << person2.age << endl;
}
};
测试代码,在main.cpp中添加
Friend xz_friend(xiaozhang); //友元类对象
xz_friend.print();
Person laoli("老李", 45); //友元类依赖
xz_friend.print2(laoli);
说明:因为声明了友元类,所以在Friend类中访问Person类的属性,也是对象.属性.
3. 友元成员函数
本书P607有相关描述,原始类和使用友元成员函数的类先后顺序有要求,需要前向声明原始类,代码如下: 1234表示顺序
class Person; //1原始类前向声明,为使用友元成员函数的类准备
class FriendFun { //2使用友元成员函数的类
double money;
public:
FriendFun(double mo) :money(mo) {}
void set_age(Person& person, int ag); //友元成员函数不能写成内联函数,必须写在外面
};
class Person { //3原始类
string name;
int age;
public:
Person(const string& str,int ag):name(str),age(ag){}
int getAge() const{ return age; }
string getName() const{ return name; }
//声明友元成员函数
friend void FriendFun::set_age(Person& person, int ag);
};
//4定义在类外的友元成员函数
void FriendFun::set_age(Person& person, int ag) {
person.age = ag; //对象.属性访问原始类私有数据
}
注意:
顺序如下:1原始类前向声明→2使用友元成员函数的类声明→3原始类声明→4友元成员函数定义
测试代码,在main.cpp中添加
//生成友元成员函数所在的类对象
FriendFun ff(5000);
//传入原始类对象,调用友元成员函数,修改原始对象数据
ff.set_age(xiaozhang,30);
//看是否改变了原始对象的数据
cout << "小张的年龄是:" << xiaozhang.getAge() << endl;
友元的分析
1.不管是哪一种友元,都是以"对象.属性"访问将其视为友元的原始类对象数据
2.如1所述,友元不能单独存在,必须要使用原始对象引用,他的形式可以是函数形参,也可以是传给友元类的属性.
友元的思考
1.友元是否破坏了数据的封装性?
不会.使用友元是为了以一种友好的方式访问私有数据.如果不使用友元,也可以通过包含对象引用,再通过接口函数来访问.和枚举一样,友元虽然不是必须的,但在某些情况下会比较方便.
2.怎样概括友元?
友元是一种授权.他授权其他成员函数或者非成员函数访问或者修改对象的私有属性.
小结
对友元的一些理解和使用.
C++在"数据可见性"上有很多的定义,比如私有公有,命名空间,类作用域,还有这里的友元.有一种简便的写法:所有数据公开,然后根据情况调整.