C++:友元(非成员友元函数、成员友元函数、友元类)
3.8 友元:友元函数和友元类
友元函数 :既可以是不属于任何类的非成员函数,也可以是另一个类的成员函数,统称为友元函数。友元函数不是当前类的成员函数,而是独立于类的外部函数,但它可以访问该类所有的成员,包括私有成员、保护成员和公有成员。在类中声明友元函数时,需在其函数名前加上关键字friend,此声明可以放在公有部分、也可以放在保护和私有部分。友元函数可以定义在类部,也可以定义在类的外部。
3.8.1 将非成员函数声明为友元函数
//1、将非成员函数声明为友元函数
// 例3.33 友元函数的使用
#include<iostream>
using namespace std;
class Gril{
public:
Gril(char* n,int a)
{
name = new char[strlen(n)+];
strcpy(name,n);
age = a;
}
~Gril()
{
delete []name;
}
friend void display(Gril &);//声明友元函数 //friend void display(Gril );
private:
char* name;
int age;
};
void display(Gril &x) //形参是对象的引用 //void display(Gril x) //形参是对象
{
cout<<"女孩的姓名是:"<<x.name<<","<<"年龄:"<<x.age<<endl;
}
int main()
{
Gril g("小丽",);
display(g); //调用友元函数,实参是对象的引用 return ;
} /*
说明:1、友元函数虽然可以访问类对象的私有成员,但它毕竟不是成员函数,因此,在类的
外部定义友元函数时,不必像成员函数那样,在函数名前加 "类名::"
2、因为友元函数不是类的成员,所以它不能直接访问对象的数据成员,也不能通过this
指针访问对象的数据成员,它必须通过作为入口参数传递进来的对象名(或对象指针、对象引用)
来访问引用对象的数据成员。
3、由于函数display是Gril类的友元函数,所以display函数可以访问Gril中私有数据成员
name、age。但是,在它们之前必须加上 "对象名."
*/
例1:非成员友元函数
/*
需求:例如有两个类Gril和Boy,现要求打印所有的男生和女生的名字和年龄,我们只需一个
独立的函数print就能完成,但它必须同时定义为这两个类的友元函数。
*/
//例如3.34 一个函数定义同时定义为两个类的友元函数
#include<iostream>
using namespace std;
class Boy; //对Boy类的提前引用声明
class Gril{
public:
Gril(char N[],int A)
{
strcpy(name,N);
age = A;
}
friend void print(Gril &x) //声明print函数是Gril类的友元函数
{
cout<<"女孩的姓名是:"<<x.name<<" "<<"年龄:"<<x.age<<endl;
}
private:
char name[];
int age;
};
class Boy{ //声明Boy类
public:
Boy(char N[],int A)
{
strcpy(name,N);
age = A;
}
friend void print(Boy &y) //声明print函数是Boy类的友元函数
{
cout<<"男孩的姓名是:"<<y.name<<" "<<"年龄:"<<y.age<<endl;
}
private:
char name[];
int age;
};
int main()
{
Gril g1("王萌",); //定义Gril类对象g1
Gril g2("李芳",); //定义Gril类对象g2
Gril g3("张丽",); //定义Gril类对象g3 Boy b1("张三",); //定义Boy类对象b1
Boy b2("李四",); //定义Boy类对象b2
Boy b3("王武",); //定义Boy类对象b3 print(g1); //调用友元函数,实参是Gril对象g1
print(g2); //调用友元函数,实参是Gril对象g2
print(g3); //调用友元函数,实参是Gril对象g3 print(b1); //调用友元函数,实参是Boy对象b1
print(b2); //调用友元函数,实参是Boy对象b2
print(b3); //调用友元函数,实参是Boy对象b3 return ;
}
例2:非成员友元函数
#include<iostream>
using namespace std;
class Boy; //对Boy类的提前引用声明
class Gril{
public:
Gril(char N[],int A)
{
strcpy(name,N);
age = A;
}
friend void print(Gril &,Boy &); //声明print函数是Gril类的友元函数
private:
char name[];
int age;
};
class Boy{ //声明Boy类
public:
Boy(char N[],int A)
{
strcpy(name,N);
age = A;
}
friend void print(Gril &,Boy &); //声明print函数是Boy类的友元函数
private:
char name[];
int age;
};
void print(Gril &x,Boy &y) //定义print有元函数
{
cout<<"女孩的姓名是:"<<x.name<<" "<<"年龄:"<<x.age<<endl;
cout<<"男孩的姓名是:"<<y.name<<" "<<"年龄:"<<y.age<<endl;
}
int main()
{
Gril g1("王萌",); //定义Gril类对象g1
Gril g2("李芳",); //定义Gril类对象g2
Gril g3("张丽",); //定义Gril类对象g3 Boy b1("张三",); //定义Boy类对象b1
Boy b2("李四",); //定义Boy类对象b2
Boy b3("王武",); //定义Boy类对象b3 print(g1,b1); //调用友元函数,实参是Gril对象g1,Boy对象b1
print(g2,b2); //调用友元函数,实参是Gril对象g2,Boy对象b2
print(g3,b3); //调用友元函数,实参是Gril对象g3,Boy对象b3 return ;
}
3.8.2将成员函数声明为友元函数
除了一般的非成员函数可以作为某个类的友元外,一个类的成员函数也可以作为另一个类的友元,它是友元函数中的一种,成为友元成员函数。友元成员函数不仅可以访问自己所在类对象中的私有成员和公有成员,还可以访问friend声明语句所在类对象中的所有成员。
例3.35 一个类的成员函数作为另一个类的友元函数
#include<iostream>
#include<string>
using namespace std;
class Gril; //对类Gril提前引用声明
class Boy{
public:
Boy(char* n,int a)
{
name = new char[strlen(n)+];
strcpy(name,n);
age = a;
}
void disp(Gril ); //声明函数dis为类Boy为成员函数
~Boy()
{
delete []name;
}
private:
char* name;
int age;
};
class Gril{
public:
Gril(char* n,int a)
{
name = new char[strlen(n)+];
strcpy(name,n);
age = a;
}
friend void Boy::disp(Gril ); //声明类Boy成员函数dis为类Gril的友元函数
~Gril()
{
delete []name;
}
private:
char* name;
int age;
};
void Boy::disp(Gril x) //定义类Boy的成员函数disp,同时也为类Gril的友元函数,
{ //形参为Gril类对象
cout<<"男孩的姓名:"<<name<<endl; //函数disp作为Boy类的成员函数 ,可以访问Boy类对象的私有成员
cout<<"男孩的年龄:"<<age<<endl; //注释同上
cout<<"女孩的姓名:"<<x.name<<endl;//函数disp作为Gril类的友元函数,可以访问Gril类对象的私有成员
cout<<"女孩的年龄:"<<x.age<<endl; //注释同上
}
int main()
{
Boy b("陈大林",);
Gril g("张晓好",);
b.disp(g);//调用Boy类的对象b的成员函数和Gril类的友元函数disp,实参是Gril类的对象g
//因为函数disp是Boy类的成员函数,所以无需通过传递对象,可以直接访问自己的私有数据成员
return ;
}
3.8.3 友元类
不仅函数可以作为一个类的友元,一个类也可以作为另一个类的友元,称为友元类。友元类
的说明方法是在另一个类声明中加入语句。
friend class 类名;
此类名是友元类的类名。这条语句可以放在公有部分,也可以放在私有部分。例如,
class Y{
...
};
class X{
...
friend class Y; //声明类Y是类X的友元类
...
};
当类Y被说明类X的友元时,类Y的所有成员函数都成为类X的友元函数,这就意味着作为
友元类Y中的所有成员函数都可以访问类X中的所有成员(包括私有成员)。
下面的例子中,声明了两个类Boy和Gril,类Boy声明为类Gril的友元,因此类Boy的成员
函数都能成为类Gril的友元函数,它们都可以访问类Gril的私有成员。
例 3.36 友元类的应用
#include<iostream>
#include<string>
using namespace std;
class Gril; //对友元类的提前引用声明
class Boy{
public:
Boy(char* n,int a)
{
name=new char[strlen(n)+];
strcpy(name,n);
age = a;
}
~Boy()
{
delete []name;
}
void display1(Gril &); //声明函数display1为类Boy的成员函数
void display2(Gril &); //声明函数display2为类Boy的成员函数
private:
char* name;
int age;
};
class Gril{
public:
Gril(char* n,int a)
{
name=new char[strlen(n)+];
strcpy(name,n);
age = a;
}
~Gril()
{
delete []name;
} friend class Boy; //声明Boy为类Gril的友元类,则类Boy中的所有成员函数为Gril类的友元成员函数 private:
char* name;
int age;
};
void Boy::display1(Gril &x)
{
cout<<"男孩的姓名是:"<<name<<endl;
cout<<"女孩的姓名是:"<<x.name<<endl;
} void Boy::display2(Gril &x)
{
cout<<"男孩的年龄是:"<<age<<endl;
cout<<"女孩的年龄是:"<<x.age<<endl;
}
int main()
{
Boy b("陈大林",);
Gril g("张晓好",); b.display1(g);
b.display2(g); return ;
}
注意:声明一个类A为另一个类B的友元类(则类A的所有成员函数都是类B的友元函数,友元类A的所有成员函数既可以访问自己本类的所有成员,也可以访问类B的所有成员)
#include<iostream>
#include<string>
using namespace std;
class Gril; //对友元类的提前引用声明
class Boy{
public:
Boy(char* n,int a)
{
name=new char[strlen(n)+];
strcpy(name,n);
age = a;
}
~Boy()
{
delete []name;
}
void display(Gril &); //声明函数display为类Boy的成员函数
private:
char* name;
int age;
};
class Gril{
public:
Gril(char* n,int a)
{
name=new char[strlen(n)+];
strcpy(name,n);
age = a;
}
~Gril()
{
delete []name;
} friend class Boy; //声明Boy为类Gril的友元类,则类Boy中的所有成员函数为Gril类的友元成员函数 private:
char* name;
int age;
};
void Boy::display(Gril &x)
{
cout<<"男孩的姓名是:"<<name<<endl;
cout<<"男孩的年龄是:"<<age<<endl;
cout<<"女孩的姓名是:"<<x.name<<endl;
cout<<"女孩的年龄是:"<<x.age<<endl;
}
int main()
{
Boy b("陈大林",);
Gril g("张晓好",); b.display(g); return ;
} /*
说明:友元关系是单向的,不具有交换性。若声明了类X是类Y的友元类(即在类Y定义中声明X为friend类),
不等于类Y一定是X的友元,这就要看在类X中是否有相应的声明。 友元关系也不具有传递性,若类X是类Y的友元,类Y是类Z的友元,不一定类X是类Z的友元。如果想让类X
是类Z的友元类,应在类Z中作出声明。
*/
C++:友元(非成员友元函数、成员友元函数、友元类)的更多相关文章
- C/C++杂记:深入理解数据成员指针、函数成员指针
1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针. 而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始地址的偏移值,空指针用-1表示.例: 代码示例: str ...
- 【转载】C/C++杂记:深入理解数据成员指针、函数成员指针
原文:C/C++杂记:深入理解数据成员指针.函数成员指针 1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针.而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始 ...
- C++运算符重载三种形式(成员函数,友元函数,普通函数)详解
首先,介绍三种重载方式: //作为成员函数重载(常见) class Person{ Private: string name; int age; public: Person(const char* ...
- About The Order of The Declarations And Definition When Making a Member Function a Friend.关于使类成员成为另一个类友元函数的声明顺序和定义。
If only member function clear of WindowMgr is a friend of Screen, there are some points need to note ...
- C++走向远洋——34(友元函数,成员函数和一般函数的区别)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:youyuan.cpp * 作者:常轩 * 微信公众号:Worl ...
- C++基础-4-封装(构造函数与析构函数,深拷贝与浅拷贝,静态成员,this,友元,const修饰成员函数)
4. 封装 4.1.1 封装的意义 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 con ...
- c++全局函数 && 成员函数
#include<iostream> using namespace std; class Test { public: Test(, ) { this->a = a; this-& ...
- cc30a_demo-CppPrimer_友元与继承-txwtech友元关系不能继承-要明确授予友元
//友元可以访问类的private与protected成员//友元关系不能继承-要明确授予友元 #include <iostream>//CppPrimer_友元与继承-txwtech-- ...
- C++_static与非static成员(函数)
static与非static成员(函数) <C++ Primer>第4版399页: 对于特定类类型的全体对象而言,访问一个全局变量有时是必要的.然而,全局变量会破坏封装:对象需要支持特定 ...
- 类成员函数作为pthread_create函数参数
from:http://www.cnblogs.com/shijingxiang/articles/5389294.html 近日需要将线程池封装成C++类,类名为Threadpool.在类的成员函数 ...
随机推荐
- 每日一“酷”之array
array--国定类型数据序列 array模块定义一个序列数据结构,看起来和list非常相似,只不过所有成员都必须是相同的基本类型. 1.初始化 array实例化时可以提高一个参数来描述允许哪个种数据 ...
- 拥抱ARM妹纸第二季 之 第二次 约会需要浪漫,这么大灯泡怎么弄?
终于轮到俺的小穆出场啦.有请能让太阳也为之暗淡的小穆闪亮登场-,鼓掌吧,欢呼吧!-- ♪♪ We can burn brighter Than the sun ~~~ ♪♪ “谢谢---“ 唱的太棒啦 ...
- 设计模式之单例模式(Singleton Pattern)
单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...
- 获取iOS设备的内存状况(转)
转载自:http://mobile.51cto.com/iphone-285371.htm iPhone这类移动设备内存有限,而又不能使用交换区,为了不至于导致内存不足而引起运行效率降低或应用崩溃 ...
- iOS 计算 日期 距离 当前 系统的日期 相差 多少
#pragma mark - 时间计算函数 - (NSTimeInterval)intervalSinceNow:(NSString *) theDate { NSDateFormatter * da ...
- 1502: [NOI2005]月下柠檬树 - BZOJ
Description Input 文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度).第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的 ...
- Nginx 301重定向域名
为何要使用301重定向 在网站建设中需要网页重定向的情况很多:如网页目录结构变动,网页重命名.网页的扩展名改变.网站域名改变等.如果不做重定向,用户的收藏和搜索引擎数据库中的旧地址只能让访客得到一个4 ...
- [原] GLES在iOS和Android上的不同
本来GLES提供了与native platform的接口 EGL, 然而iOS没有使用EGL接口, 而是自己搞了一套,叫做EAGL的类似东西, 虽然说大同小异,但是在做跨平台的时候还是很恶心. elg ...
- 【log4net】配置文件
相关资料: http://www.cnblogs.com/dragon/archive/2005/03/24/124254.html 注意: //如果为了使得应用程序的配置文件(web/app.con ...
- netbean使用技巧
1.让代码智能提示 有些情况下Ctrl+Space这个键被一些输入法占了,我们需要修改一下点击 工具->常规->快捷键映射->找到显示代码完成弹出式菜单->编辑为你喜欢的键就好 ...