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.在类的成员函数 ...
随机推荐
- Jquery插件收集
移动端滚动条插件iScroll.js http://www.cnblogs.com/starof/p/5215845.html http://www.codeceo.com/article/35-jq ...
- Windows C盘格式化或者同平台迁移oracle数据库
我们知道如果是Linux 同平台迁移oracle数据库.只要是安全关闭了数据库,在新机器上创建用户组,配置了环境变量,将数据库安装目录拷贝到对应的目录就好用了. 一直在寻求Windows平台上这类的解 ...
- LAMP开发之环境搭建(2014.12.7在ubuntu下)
Ubuntu下搭建LAMP环境 前言:学习PHP脚本编程语言之前,必须先搭建并熟悉开发环境,开发环境有很多种,例如LAMP.WAMP.MAMP等.这里我搭建的是LAMP环境,即Linux.Apache ...
- 1100. Mars Numbers (20)
People on Mars count their numbers with base 13: Zero on Earth is called "tret" on Mars. T ...
- iOS中使用自定义字体
1.确定你的项目工程的Resources下有你要用的字体文件(.ttf或者.odf). 2.然后在你的工程的Info.plist文件中新建一行,添加key为:UIAppFonts,类型为Array或D ...
- Java高效读取大文件
1.概述 本教程将演示如何用Java高效地读取大文件.这篇文章是Baeldung (http://www.baeldung.com/) 上“Java——回归基础”系列教程的一部分. 2.在内存中读取 ...
- cocos2dx中的三种基本的数据类型
cocos2dx中提供了三种基本的数据类型:CCString(字符串),CCArray(数组),CCDictionary(数据字典(哈希的功能)) 2.CCString的用法 class CCStr ...
- 计划:怎样理解水平集方法 ITK Level set V4 框架介绍
简易解释:在曲面中插入一个平面所形成的轮廓,即是该轮廓的水平集表示,可见,该轮廓的水平集表示有多个.对于图像分割,在图像力的驱动下曲面进行更新. 轮廓的数学表达有隐式和显式两种表达.用曲面演化代替Fr ...
- Ubuntu 常用软件安装方法
macubuntu 安裝方法: $wget https://github.com/downloads/ChinaLuo/Mac_Ubuntu/Mac_Ubuntu-12.04.tar.gz -O /t ...
- 从状态转移看:载波侦听多路访问/冲突避免(CSMA/CA)
CSMA/CA是写入IEEE802.11的无线网络MAC层标准协议,相信看到这篇文章的读者都知道它是用来做什么的.但许多短文对这个协议的解释都有所缺乏,因此本文用状态转换图的形式详细说明协议的工作流程 ...