C++中友元(友元函数和友元类)的用法和功能

http://blog.csdn.net/adriano119/article/details/5914443/

采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

友元函数  
       友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
       friend 类型 函数名(形式参数);

       友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
       一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
       友元函数的调用与一般函数的调用方式和原理一致。

友元类  
       友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。       
       当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
       friend class 类名;
       其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

       例如,以下语句说明类B是类A的友元类:
       class A
       {
              …
       public:
              friend class B;
              …
       };
       经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。

       使用友元类时注意:
             (1) 
友元关系不能被继承。 
             (2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B
的友元,要看在类中是否有相应的声明。
             (3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明

《windows环境多线程编程原理与应用》中解释:

  如果将类的封装比喻成一堵墙的话,那么友元机制就像墙上了开了一个门,那些得

  到允许的类或函数允许通过这个门访问一般的类或者函数无法访问的私有属性和方   

  法。友元机制使类的封装性得到消弱,所以使用时一定要慎重。

  ■ 友元类的说明

   将外界的某个类在本类别的定义中说明为友元,那么外界的类就成为本类的“朋  

   友”,那个类就可以访问本类的私有数据了。

   class Merchant

      {

          private :

             int m_MyMoney;

             int m_MyRoom;

             … …

          Public:

             Friend class Lawyer;

             Int getmoney();

             … …

      };

      Class Lawyer

     {

        Private:

          … …

        Public:

         … …

     };

     只有你赋予某个类为你的友元时,那个类才有访问你的私有数据的权利。

  ■ 说明一个函数为一个类的友元函数则该函数可以访问此类的私有数据和方法。定

   义方法是在类的定义中,在函数名前加上关键字friend.

挑战30天C/C++》这样解释:

  在说明什么是友元之前,我们先说明一下为什么需要友元与友元的缺点: 
通常对于普通函数来说,要访问类的保护成员是不可能的,如果想这么做那么必须把类的成员都生命成为public(共用的),然而这做带来的问题遍是任何外部函数都可以毫无约束的访问它操作它,c++利用friend修饰符,可以让一些你设定的函数能够对这些保护数据进行操作,避免把类成员全部设置成public,最大限度的保护数据成员的安全。 
友元能够使得普通函数直接访问类的保护数据,避免了类成员函数的频繁调用,可以节约处理器开销,提高程序的效率,但所矛盾的是,即使是最大限度大保护,同样也破坏了类的封装特性,这即是友元的缺点,在现在cpu速度越来越快的今天我们并不推荐使用它,但它作为c++一个必要的知识点,一个完整的组成部分,我们还是需要讨论一下的。 
在类里声明一个普通数学,在前面加上friend修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员。

   下面我们来看一段代码,看看我们是如何利用友元来访问类的一切成员的

       //程序作者:管宁 
//
站点:www.cndev-lab.com 
//
所有稿件均有版权,如要转载,请务必著名出处和作者 
#include <iostream
using namespace std; 
class Internet 

public
Internet(char *name,char *address) // 
改为:internet(const char *name , const char *address)

strcpy(Internet::name,name); 
strcpy(Internet::address,address); 

friend void ShowN(Internet &obj);   //
友元函数的声明 
public
// 改为:private
char name[20]; 
char address[20]; 
}; 
void ShowN(Internet &obj)        //
函数定义,不能写成,void Internet::ShowN(Internet &obj) 

cout<<obj.name<<endl;          //
可访问internet类中的成员

void main() 

Internet a("
中国软件开发实验室","www.cndev-lab.com"); 
ShowN(a); 
cin.get(); 

上面的代码通过友元函数的定义,我们成功的访问到了a对象的保护成员name,友元函数并不能看做是类的成员函数,它只是个被声明为类友元的普通函数,所以在类外部函数的定义部分不能够写成void Internet::ShowN(Internet &obj),这一点要注意。

================================================================================

实例:

分别定义一个类A和类B ,各有一个私有整数成员变量通过构造函数初始化;类A有一个成员函数Show(B &b)用来打印A和B的私有成员变量,请分别通过友元函数和友元类来实现此功能。

 

用友元类 和 友元函数做出来的


#include <iostream>

using namespace std;

class B;
class A;
void Show( A& , B& );

class B
{
private:
int tt;
friend class A;
friend void Show( A& , B& );

public:
B( int temp = 100):tt ( temp ){}

};


class A
{
private:
int value;
friend void Show( A& , B& );

public:
A(int temp = 200 ):value ( temp ){}

void Show( B &b )
{
  cout << value << endl;
  cout << b.tt << endl; 
}
};

void Show( A& a, B& b )
{
cout << a.value << endl;
cout << b .tt << endl;
}

int main()
{
A a;
B b;
a.Show( b );
Show( a, b );

      return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线程的终止分离

1.线程的终止 注意该函数是针对用户级别的, 其中 retal 必须指向一个全局变量, 或者是一个 malloc 分配的, 因为如果是线程的局部变量, 当该线程退出时, 其他线程不能得到这个变量, 因为线程的局部变量各自私有 2. 现成的取消 其中thread是线程的 tid 3.线程的等待与分离 (1)…

UVa10082

【题目描述】 传送门 【题目分析】 同样是一道模拟&#xff0c;但是如何巧妙快速的解决仍然不简单。通过这道题告诉我们对于复杂确定的对应关系我们要灵活运用常量数组。 同时还需要注意的一个小问题就是字符串数组中的"//"指的是转义后的单斜杠&#xff0c;如果只…

C语言中的深拷贝和浅拷贝

http://www.cnblogs.com/zhanggaofeng/p/5421804.html C语言中的深拷贝和浅拷贝 //C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h>typedef struct _student{char name[30];char *title;…

死锁的产生和避免

1.死锁产生的四个必要条件 (1)互斥条件&#xff1a;资源是独占的且排他使用&#xff0c;进程互斥使用资源&#xff0c;即任意时刻一个资源只能给一个进程使用&#xff0c;其他进程若申请一个资源&#xff0c;而该资源被另一进程占有时&#xff0c;则申请者等待直到资源被占有者…

UVa401

【题目描述】 传送门 【题目描述】 嘻嘻&#xff0c;自己做直接AC还是比较开心的。当然有一部分原因是之前看书的时候详细看过这个题的代码&#xff0c;但是这已经快一年了&#xff0c;应该说做出这道题凭借的是自己的能力吧。回过身去看了一下书中的代码发现自己写的不算复…

gethostbyname() 函数说明

https://www.cnblogs.com/cxz2009/archive/2010/11/19/1881611.html gethostbyname()函数说明——用域名或主机名获取IP地址 包含头文件#include <netdb.h>#include <sys/socket.h>函数原型struct hostent *gethostbyname(const char *name);这个函数的传入值是域…

求解迷宫最短路径

1. 多通路迷宫初始化 先构建一个多通路迷宫,并且对其初始化 void MazeInitShortPath(Maze* maze) {if(maze NULL){return;}int row 0;int col 0;for(; row < MAX_COL; row){for(col 0; col < MAX_COL; col){maze -> map[row][col] Map[row][col];}printf("…

UVa340

【题目描述】 传送门 【题目分析】 题目理解以后十分简单&#xff0c;但是这题面实在让人自闭&#xff0c;这么简单的题目啦啦啦啦说了那么多&#xff0c;实在是看不懂。&#xff08;幸亏我看了书理解了题目的意思&#xff0c;要不然。。&#xff09;还是要锻炼自己的读题能…

C语言:结构体中一级指针和二级指针的创建与释放示例

http://blog.csdn.net/Bixiwen_liu/article/details/53610952 这几天把C语言巩固了一下&#xff0c;作为一门最基本的编程语言&#xff0c;C语言还是相当基础和非常重要的&#xff0c;个人认为C语言还是很有必要学好吃透的。 今天写的话题是结构体结构体中一级指针和二级指针的…

带环迷宫求最短路径

前面介绍了简单的迷宫求解问题, 今天我们就对带环迷宫求出它的最短路径 1.首先来看一个带环迷宫的简单地图 在这张迷宫地图中,我们规定入口点的位置entry的坐标是 (0, 1), 同时, 我们给入口点传一个非法坐标,作为入口点的前一个位置(-1, -1). 接下来的思路就和上一篇的思路是一…

UVa1583

【题目描述】 传送门 【题目分析】 我以为很简单就写了一个暴力没有想到超时了。应该是T是非常大的所以必须得打表&#xff0c;将所有的结果都储存起来然后直接输出。 以后遇到这种可以一下算出所有结果的多组数据最好还是算出所有的结果然后再输出答案。 【AC代码】 #inc…

C 结构体嵌套一级指针 二级指针 动态分配内存

https://blog.csdn.net/xielinhua88/article/details/51364623 点击打开链接 #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> //结构体嵌套一级指针 二级指针 动态分配内存 typedef struct _Teacher { int ag…

线程的同步与互斥

1. 互斥量 在Linux 下线程使用的都是局部变量, 而我们知道, 每一个线程都独立拥有自己的一个栈, 而这些局部便令就在栈中,而线程的创建就是为了实现通信, 此时线程之间无法共享这些变量     为了使得线程之间能够共享数据, 一次我们可以创建一个全局变量, 此时线程都在进程…

二级指针与指针数组的关系

http://blog.csdn.net/shuaishuai80/article/details/6129742 #include <stdio.h> void test(char *argv[]); int main(void) { char *argv[3]{{"abcdefg"},{"1234567"},{"q1w2e3r"}}; test(argv); /*调用指针数组…

UVa1584

【题目描述】 传送门 【题目分析】 也是一道简单的模拟题&#xff0c;1A嘿嘿嘿。 再看书发现和书上的做法差不多。 【AC代码】 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<cstd…

cf#582div3 D——暴力

【题目描述】 The only difference between easy and hard versions is the number of elements in the array.You are given an array a consisting of n integers. In one move you can choose any ai and divide it by 2 rounding down (in other words, in one move you c…

C语言 可变参数

http://www.cnblogs.com/zhanggaofeng/p/6434554.html //可变参数 #include <stdio.h> #include <stdlib.h> #include <string.h> //引用头文件 #include <stdarg.h>/* va_list用于声明一个变量&#xff0c;我们知道函数的可变参数列表其实就是一个字符…

UVa1585

【题目描述】 传送门 【题目分析】 氵 【AC代码】 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<cstdlib> #include<set> #include<map> #include<vector>u…

c语言经典算法——查找一个整数数组中第二大数

https://www.cnblogs.com/dootoo/p/4473958.html 题目&#xff1a; 实现一个函数&#xff0c;查找一个整数数组中第二大数。 算法思想&#xff1a; 设置两个变量max1和max2&#xff0c;用来保存最大数和第二大数&#xff0c;然后将数组剩余的数依次与这两个数比较&#xff0c;如…

进程间关系和守护进程

一. 进程组/作业/会话 1.进程组 每一个进程除了有一个进程ID之外, 还属于一个进程组. 进程是一个或多个进程的集合. 通常, 它们与同一个作业向关联, 可以接收来自同一个终端下的各种命令,信号. 每一个进程组都有唯一的进程组 ID. 每一个进程组都可以有一个组长进程. 组长进程的…