原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/

有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的。例如被重载的操作符,如输入或输出操作符,经常需要访问类的私有数据成员。

友元(frend)机制允许一个类将对其非公有成员的访问权授予指定的函数或者类,友元的声明以friend开始,它只能出现在类定义的内部,友元声明可以出现在类中的任何地方:

  友元不是授予友元关系的那个类的成员,所以它们不受其声明出现部分的访问控制影响。通常,将友元声明成组地放在类定义的开始或结尾是个好主意。

1普通函数友元函数

友元函数是指某些虽然不是类成员函数却能够访问类的所有成员的函数。类授予它的友元特别的访问权,这样该友元函数就能访问到类中的所有成员。

  目的:使普通函数能够访问类的友元

  声明: friend + 普通函数声明

  实现位置:可以在类外或类中

  实现代码:与普通函数相同

  调用:类似普通函数,直接调用

#include <iostream>  

using namespace std;  

class Atest
{
public:
Atest()
:value()
{}
~Atest(){}
private:
friend void function(Atest&);//该函数是友元函数的声明
int value;
static int sta_val;
}; void function(Atest& test)//友元函数定义,为了访问类Atest中的成员
{
cout <<"value is "<<test.value<<endl;
cout <<"static is "<<Atest::sta_val<<endl;
} int Atest::sta_val = ; int main(int argc, char const *argv[])
{
Atest struct_val; function(struct_val);
return ;
}

執行結果:

2Y的所有成员函数都为类X友元函数友元类

 友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。

关于友元类的注意事项:

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

目的:使用单个声明使Y类的所有函数成为类X的友元,它提供一种类之间合作的一种方式,使类Y的对象可以具有类X和类Y的功能。

  声明位置:公有私有均可,常写为私有(把类看成一个变量)

  声明: friend + class +类名;(不是对象哦)

#include <iostream>  

using namespace std;  

class Bstruct
{
public:
Bstruct()
:Bvalue(),name((char*)"ZHOU"){}
friend class Astruct;//这是友元类的声明
private:
int Bvalue;
char* name;
}; class Astruct//友元类定义,为了访问类Bstruct中的成员
{
public:
void function(Bstruct&);
}; void Astruct::function(Bstruct& str)
{
cout <<"Bvalue is "<<str.Bvalue<<", name is "<<str.name<<endl;
} int main(int argc, char const *argv[])
{
Astruct A;
Bstruct B; A.function(B); return ;
}

執行結果:

3。Y的一个成员函数为类X的友元函数

使类B中的成员函数成为类A的友元函数,这样类B的该成员函数就可以访问类A的所有成员了。

当用到友元成员函数时,需注意友元声明和友元定义之间的相互依赖,在该例子中,类B必须先定义,否则类A就不能将一个B的函数指定为友元。然而,只有在定义了类A之后,才能定义类B的该成员函数。

  更一般的讲,必须先定义包含成员函数的类,才能将成员函数设为友元。另一方面,不必预先声明类和非成员函数来将它们设为友元。

  目的:使类Y的一个成员函数成为类X的友元,具体而言:在类Y的这个成员函数中,借助参数X,可以直接以X的私有变量

  声明位置:声明在公有中 (本身为函数)

  声明:friend + 成员函数的声明

  调用:先定义Y的对象y---使用y调用自己的成员函数---自己的成员函数中使用了友元机制

#include <iostream>  

using namespace std;  

class Bstruct;//当用到友元成员函数时,需注意友元声明与友元定义之间的互相依赖。这是类Bstruct的声明 

class Astruct
{
public:
void function(Bstruct&);//该函数是类Bstruct的友元函数
}; class Bstruct
{
public:
Bstruct()
:Bvalue(),name((char*)"ZHOU"){}
friend void Astruct::function(Bstruct&);//该函数是友元成员函数的声明
int Bvalue;
char* name;
}; void Astruct::function(Bstruct& str)//只有在定义类Bstruct后才能定义该函数,毕竟,它被设为友元是为了访问类Bstruct的成员
{
cout <<"Bvalue is "<<str.Bvalue<<", name is "<<str.name<<endl;
} int main(int argc, char const *argv[])
{ Bstruct B;
Astruct A;
A.function(B); return ;
}

執行結果:

友元函数和类的成员函数的区别

1 成员函数有this指针,而友元函数没有this指针。

2 友元函数是不能被继承的,就像父亲的朋友未必是儿子的朋友。

  

c++友元函數---16的更多相关文章

  1. Oracle排序函數Rank

    出口給報關行出貨的時候,同一票shipment中合併多個invoice跟packing,轉出到廠商的報關系統時候,出口報關的序號會將invoice的序號做自動增加. 因為wafer會有出口給其他外包做 ...

  2. oracle decode(nvl(estimate_qty,0),0,1,estimate_qty) 函數

    oracle   decode(nvl(estimate_qty,0),0,1,estimate_qty) 函數

  3. js匿名函數

    (function($){})(jquery) == (function($){})(jQuery) 实际上是匿名函数 用于存放开发插件的代码 作用(非常有用): 这种写法的最大好处是形成闭包.在(f ...

  4. Math.Round函數

    Math.Round這個函數的解釋是將值按指定的小數位數舍入,但並不就是四捨五入.這種舍入有時稱為就近舍入或四舍六入五成雙 其實在 VB, VBScript, C#, J#, T-SQL 中 Roun ...

  5. C#判断奇偶数的函數

    // 现代流行的"程序员" public static bool IsOdd(int n) { while (true) { switch (n) { : return true; ...

  6. PHP 計算字符串長度函數

    PHP內置的字符串長度函數strlen無法正確處理中文字符串,它得到的只是字符串所占的字節數.對於GB2312的中文編碼,strlen得到的值是漢字個數的2倍,而對於UTF-8編碼的中文,就是3倍的差 ...

  7. SQL窗体函數一例

    需求: MSSQL,列出服務實例中全部數據庫的例如以下信息: 數據庫ID.數據庫名.創建日期.數據文件類型.數據文件大小.數據庫總大小.文件所在路徑. 寫法(後面的百分比為所花時間占比): -- 连接 ...

  8. js函數

    函數是什麼?函數就是被事件驅動或者調用執行的可重複的代碼塊. 函數聲明: 使用關鍵詞function,關鍵詞function大小敏感. function a{代碼塊} 局部變量: 在函數內部聲明的變量 ...

  9. concat函數 函數concat 可以用來合拼兩個或以上的字串。

    12. “Mexico 墨西哥”的首都是”Mexico City”. 顯示所有國家名字,其首都是國家名字加上”City”. concat函數 函數concat 可以用來合拼兩個或以上的字串. : SE ...

随机推荐

  1. docker原理

    Docker原理11 Linux Namespace 11 AUFS文件系统17 重新理解Docker的各种命令18 Docker原理 Linux Namespace docker是一个容器引擎,容器 ...

  2. Web API设计方法论

    英文原文:A Web API Design Methodology 为Web设计.实现和维护API不仅仅是一项挑战:对很多公司来说,这是一项势在必行的任务.本系列将带领读者走过一段旅程,从为API确定 ...

  3. 【C】——利用sigsuspend函数等待信号阻塞进程

    #include<signal.h> int sigsuspend(const sigset_t *sigmask); 返回值:-,并将errno设置为EINTR 将进程的信号屏蔽字设置为 ...

  4. CSS(九):设置盒子水平垂直居中

    通过设置下面的样式可以使盒子水平垂直居中: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  5. 根据map键值对,生成update与select语句,单条执行语句

    方法 constructUpdateSQL private static String constructUpdateSQL(String tableName, List<Map<Stri ...

  6. Android-FragmentPagerAdapter刷新无效的解决方案

    按照通常使用ListView的习惯做法,如果你只是更新保存Fragment的List数据,然后调用adapter的notifyDataSetChanged()是不会起作用的. 搜索了下发现此问题普遍存 ...

  7. php时间段判断

    <?php function times(){ ini_set('date.timezone','Asia/Shanghai'); $time = date("Y-m-d H:i&qu ...

  8. IDEA 创建git 分支 拉取分支

        此时只是在本地创建好了分支,修改源代码后add,commit将本地分支提交到远程仓库          分支已创建,其它成员此时就可以从git拉分支

  9. 【转】【Python】Python中的__init__.py与模块导入(from import 找不到模块的问题)

    python中的Module是比较重要的概念.常见的情况是,事先写好一个.py文 件,在另一个文件中需要import时,将事先写好的.py文件拷贝 到当前目录,或者是在sys.path中增加事先写好的 ...

  10. 转:ios Sqlite数据库增删改查基本操作

    研究了几天的数据库,终于把它给搞出来了.Sqlite是ios上最常用的数据库之一,大家还是有必要了解一下的.这是仿照网上的一个例子做的,有些部分写的不好,我稍作了修改,以讲解为主,主要让大家能够明白如 ...