`

C++友元函数的分析和理解

 
阅读更多
参考链接
http://blog.csdn.net/insistgogo/article/details/6608672
http://www.cnblogs.com/fzhe/archive/2013/01/05/2846808.html

1、为什么要引入友元函数:在实现类之间数据共享时,减少系统开销,提高效率
    具体来说:为了使其他类的成员函数直接访问该类的私有变量
    即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数
    优点:能够提高效率,表达简单、清晰
    缺点:友元函数破环了封装机制,尽量不使用成员函数,除非不得已的情况下才使用友元函数。

2、什么时候使用友元函数:
    1)运算符重载的某些场合需要使用友元。
    2)两个类要共享数据的时候

3、怎么使用友元函数
    友元函数的参数
       因为友元函数没有this指针,则参数要有三种情况:
       1、  要访问非static成员时,需要对象做参数;--常用(友元函数常含有参数)
       2、  要访问static成员或全局变量时,则不需要对象做参数
       3、  如果做参数的对象是全局对象,则不需要对象做参数

    友元函数的位置
       因为友元函数是类外的函数,所以它的声明可以放在类的私有段或公有段且没有区别。

    友元函数的调用
       可以直接调用友元函数,不需要通过对象或指针


    友元函数的分类
    根据这个函数的来源不同,可以分为三种方法:
1、普通函数友元函数:
    a) 目的:使普通函数能够访问类的友元
    b) 语法:声明位置:公有私有均可,常写为公有
           声明: friend + 普通函数声明
           实现位置:可以在类外或类中
           实现代码:与普通函数相同(不加不用friend和类::)
           调用:类似普通函数,直接调用


2、类Y的所有成员函数都为类X友元函数—友元类
    a)目的:使用单个声明使Y类的所有函数成为类X的友元
           它提供一种类之间合作的一种方式,使类Y的对象可以具有类X和类Y的功能
           具体来说:
               前提:A是B的友元(=》A中成员函数可以访问B中有所有成员,包括私有成员和公有成员--老忘)
               则:在A中,借助类B,可以直接使用~B . 私有变量~的形式访问私有变量

    b)语法:声明位置:公有私有均可,常写为私有(把类看成一个变量)
           声明: friend + 类名---不是对象啊
           调用:


3、类Y的一个成员函数为类X的友元函数
    a)目的:使类Y的一个成员函数成为类X的友元
           具体而言:而在类Y的这个成员函数中,借助参数X,可以直接以X。私有变量的形式访问私有变量
     b)语法:声明位置:声明在公有中 (本身为函数)
            声明:friend + 成员函数的声明
            调用:先定义Y的对象y---使用y调用自己的成员函数---自己的成员函数中使用了友元机制


4、在模板类中使用友元operator<<(对<<运算符的重载)
    a)使用方法:
    在模板类中声明:
friend ostream& operator<< <>(ostream& cout,const MGraph<VexType,ArcType>& G);
 
    在模板类中定义:
template<class VexType,class ArcType>  
ostream& operator<<(ostream& cout,const MGraph<VexType,ArcType>& G)  
{  
    //函数定义  
}
 
    b)注意:
        把函数声明非模板函数:
friend ostream& operator<< (ostream& cout,const MGraph& G);
 
        把函数声明为模板函数:
friend ostream& operator<< <>(ostream& cout,const MGraph<VexType,ArcType>& G);  
或:
friend ostream& operator<< <VexType,ArcType>(ostream& cout,const MGraph<VexType,ArcType>& G); 

        说明:
            在函数声明中加入operator<< <>:是将operator<<函数定义为函数模板,将函数模板申明为类模板的友员时,是一对一绑定的
            实际的声明函数:这里模板参数可以省略,但是尖括号不可以省略


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

友元函数和类的成员函数的区别:成员函数有this指针,而友元函数没有this指针。

记忆:A是B的友元《=》A是B的朋友《=》借助B的对象,在A中可以直接 通过B。成员变量(可以是公有,也可以为私有变量) 的方式访问B



//测试一:普通函数友元函数
//////////////////////////////////////////////////////////////////////////
class IntegerNumber
{
//////////////////////////////////////////////////////////////////////////
public:
    void SetNumber(int a, int b, int c)
    {
        m_nPublicNumber = a;
        m_nProtectedNumber = b;
        m_nPrivateNumber= c;
    }

//////////////////////////////////////////////////////////////////////////
public:
     void PrintPublicNumber()
     {
         cout<<"[PrintPublicMethod] Public Number is " << m_nPublicNumber << endl;
     }

protected:
    void PrintProtectedNumber()
    {
        cout<<"[PrintProtectedMethod] Protected Number is " << m_nProtectedNumber << endl;
    }

private:
    void PrintPrivateNumber()
    {
        cout<<"[PrintPrivateMethod] Private Number is " << m_nPrivateNumber << endl;
    }

//////////////////////////////////////////////////////////////////////////
//由于友元函数没有this指针,所以一般要求用户传入友元函数所在类的一个对象
//结论一:声明友元函数,友元函数的访问权限不受 public | protected | private 影响
public:
    friend void PublicFriend(IntegerNumber& number)
    {
        cout << "--------------------------------------------------------\n";
                                                                                             //结论二:友元函数可以访问对象的所有成员
        cout << "[PublicFriend] Public Number is " << number.m_nPublicNumber << endl;        //友元函数可以访问公有成员
        cout << "[PublicFriend] Protecdted Number is " << number.m_nProtectedNumber << endl; //友元函数可以访问保护成员
        cout << "[PublicFriend] Private Number is " << number.m_nPrivateNumber << endl;      //友元函数可以访问私有成员

                                         ////结论三:友元函数可以访问对象的所有方法
        number.PrintPublicNumber();      //友元函数可以访问公有方法
        number.PrintProtectedNumber();   //友元函数可以访问保护方法
        number.PrintPrivateNumber();     //友元函数可以访问私有方法
    }

protected:
    friend void ProtectedFriend(IntegerNumber& number)
    {
        cout << "--------------------------------------------------------\n";
        cout << "[ProtectedFriend] Public Number is " << number.m_nPublicNumber << endl;        //友元函数可以访问公有成员
        cout << "[ProtectedFriend] Protecdted Number is " << number.m_nProtectedNumber << endl; //友元函数可以访问保护成员
        cout << "[ProtectedFriend] Private Number is " << number.m_nPrivateNumber << endl;      //友元函数可以访问私有成员

        number.PrintPublicNumber();      //友元函数可以访问公有方法
        number.PrintProtectedNumber();   //友元函数可以访问保护方法
        number.PrintPrivateNumber();     //友元函数可以访问私有方法
    }

private:
     friend void PrivateFriend(IntegerNumber& number)
     {
         cout << "--------------------------------------------------------\n";
         cout << "[PrivateFriend] Public Number is " << number.m_nPublicNumber << endl;        //友元函数可以访问公有成员
         cout << "[PrivateFriend] Protecdted Number is " << number.m_nProtectedNumber << endl; //友元函数可以访问保护成员
         cout << "[PrivateFriend] Private Number is " << number.m_nPrivateNumber << endl;      //友元函数可以访问私有成员

         number.PrintPublicNumber();      //友元函数可以访问公有方法
         number.PrintProtectedNumber();   //友元函数可以访问保护方法
         number.PrintPrivateNumber();     //友元函数可以访问私有方法
     }

//////////////////////////////////////////////////////////////////////////
public:
    int m_nPublicNumber;

protected:
    int m_nProtectedNumber;

private:
    int m_nPrivateNumber;
};

//////////////////////////////////////////////////////////////////////////
void FriendMethodTest()
{
    IntegerNumber cNumber;
    cNumber.SetNumber(8, 9, 10);

    //友元函数只能采取以下直接调用的方式
    //////////////////////////////////////////////////////////////////////////
    PublicFriend(cNumber);//直接调用
    ProtectedFriend(cNumber);//直接调用
    PrivateFriend(cNumber);//直接调用


    // C2039: 'PublicFriend' : is not a member of 'IntegerNumber'
    //cNumber.PublicFriend(cNumber);   //友元函数无法采用一般成员函数的调用方式

    //error C2039: 'ProtectedFriend' : is not a member of 'IntegerNumber'
    //cNumber.ProtectedFriend(cNumber); //友元函数无法采用一般成员函数的调用方式

    //error C2039: 'PrivateFriend' : is not a member of 'IntegerNumber'
    //cNumber.PrivateFriend(cNumber);     //友元函数无法采用一般成员函数的调用方式
}

void NormalMethodTest()
{
    IntegerNumber cNumber;
    cNumber.SetNumber(8, 9, 10);

    //正常情况下,对象只能访问公有成员,无法访问保护成员和私有成员。
    //////////////////////////////////////////////////////////////////////////
    cout << "Public Number is " << cNumber.m_nPublicNumber << endl;        //一般对象可以访问公有成员

    //error C2248: 'IntegerNumber::m_nProtectedNumber' : cannot access protected member declared in class 'IntegerNumber'
    //cout << "Protecdted Number is " << cNumber.m_nProtectedNumber << endl; //一般对象无法访问保护成员

    //error C2248: 'IntegerNumber::m_nPrivateNumber' : cannot access private member declared in class 'IntegerNumber'
    //cout << "Private Number is " << cNumber.m_nPrivateNumber << endl;      //一般对象无法访问私有成员


    //正常情况下,对象只能访问公有方法,无法访问保护方法和私有方法。
    //////////////////////////////////////////////////////////////////////////
    cNumber.PrintPublicNumber();    //一般对象可以访问公有方法

    //error C2248: 'IntegerNumber::PrintProtectedNumber' : cannot access protected member declared in class 'IntegerNumber'
    //cNumber.PrintProtectedNumber(); //一般对象无法访问保护方法

    //error C2248: 'IntegerNumber::PrintPrivateNumber' : cannot access private member declared in class 'IntegerNumber'
    //cNumber.PrintPrivateNumber();   //一般对象无法访问私有方法
}


void main()
{
    NormalMethodTest();
    FriendMethodTest();
}





//测试二:指定其他类的方法为自己的友元函数
class Girl;

class Boy
{
public:
    Boy(int nId, int nAge)
    {
        m_nID = nId;
        m_nAge = nAge;
    }

    void Display(Girl& girl);

private:
    int m_nID;
    int m_nAge;
};

class Girl
{
public:  
    Girl(int nId, int nAge)
    {
        m_nID = nId;
        m_nAge = nAge;
    }

    //声明类Boy的成员函数DispGirl()为类Girl的友元函数
    friend void Boy::Display(Girl& girl);

private:
    int m_nID;
    int m_nAge;
};

void Boy::Display(Girl& girl)
{
    //访问自己(Boy)的对象成员,直接访问自己的私有变量 
    cout  <<  "Boy's id is:"  <<  m_nID  <<  ",age:"  <<  m_nAge  <<  endl;

    //借助友元,在Boy的成员函数disp中,借助Girl的对象,直接访问Girl的私有变量
    //正常情况下,只允许在Girl的成员函数中访问Girl的私有变量  
    cout  <<  "Girl's id is:"  <<  girl.m_nID<<  ",age:"  <<  girl.m_nAge  <<endl;
}

void FriendMethodByOtherClassTest()
{   
    Boy b(123, 18);
    Girl g(345, 20);
    b.Display(g);
}

void main()
{
    FriendMethodByOtherClassTest();
}




//测试三:友元类,可以访问类的全部函数,可以理解成特殊的友元函数
class Wife;
class Husband
{  
private:
    int m_nMoney;

public:  
    Husband(int nMoney)
    {
        m_nMoney = nMoney;
    }

    void Display(Wife& wife);
};

class Wife
{
private:
    int m_nMoney;

    friend Husband;   //声明类Husband是类Wife的友元类

public:
    Wife(int nMoney)
    {
        m_nMoney = nMoney;
    }
};

//函数Display()为类Husband的成员函数,也是类Wife的友元函数 
void Husband::Display(Wife& wife) 
{ 
    //正常情况,Husband的成员函数disp中直接访问Husband的私有变量
    cout  <<  "Husband's money is:"  <<  m_nMoney  <<  endl;

    //借助友元类,在Husband的成员函数disp中,借助Wife的对象,直接访问Wife的私有变量
    //正常情况下,只允许在Wife的成员函数中访问Wife的私有变量
    cout  <<  "Wife's money is:"  <<  wife.m_nMoney  <<endl;
}

void FrientClassTest()
{   
    Husband h(123);
    Wife w(456);
    h.Display(w);  //h调用自己的成员函数,但是以w为参数,友元机制体现在函数Display中
}

void main()
{
    FrientClassTest();
}




//测试四:友元函数进行操作符重载
#include <iostream>
#include <string>
using namespace std;

class rect {
    int x1, y1, x2, y2;    //矩形座标
public:
    rect() {
        x1 = 0, y1 = 0, x2 = 0, y2 = 0;
    }
    rect(int m1, int n1, int m2, int n2) {
        x1 = m1, y1 = n1, x2 = m2, y2 = n2;
    }
    void print() {
        cout << "  x1=" << x1;
        cout << "  y1=" << y1;
        cout << "  x2=" << x2;
        cout << "  y2=" << y2;
        cout << endl;
    }
    //rect operator++();                 //这是类的运算符的重载
    friend rect operator++(rect &ob);   //这是全局运算符的重载
};

rect operator++(rect &ob) {
    ob.x1++, ob.y1++; 
    ob.x2++, ob.y2++;

    return ob;
}

int main ( )
{
    rect r(12, 20, 50, 40);
    r.print();

    rect obj;
    obj = r++;
    obj.print();

    return 0;
}
分享到:
评论

相关推荐

    C++友元函数及友元类全总结

    ### C++友元函数及友元类全总结 #### 一、引言 在C++编程语言中,封装性是一个非常重要的概念。封装使得对象的数据成员(尤其是私有成员)和成员函数得以隐藏,从而提高了代码的安全性和可维护性。然而,在某些...

    c++友元函数与友元类的深入解析

    友元函数和友元类的需要:类具有封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又...

    C++友元成员函数使用实例

    首先,让我们理解友元函数的基本概念。友元函数不是类的成员,但它被声明为某个类的友元,因此它可以访问该类的所有私有和受保护成员。通常,友元函数定义在类的外部,但与类有紧密的关系。友元函数通过在类的声明中...

    C++运算符重载 成员函数与友元函数详解

    总的来说,C++的运算符重载使得我们能够为自定义类型设计符合自然语言习惯的运算行为,成员函数和友元函数提供了实现这一目标的灵活工具。通过了解和掌握这两种方法,开发者可以编写出更加直观、易于理解的代码。

    友元函数代码实例

    友元函数,类外普通函数声明为类的友元,之后即可与类共享数据

    c++ 友元函数入门教程

    虽然它能提供一定的便利和效率提升,但使用时需谨慎,因为过度依赖友元函数可能导致代码难以理解和维护,且破坏了面向对象编程中的封装原则。在设计时,应优先考虑使用公有成员函数和访问器/修改器方法,仅在必要时...

    C++友元习题.pdf

    本摘要信息涵盖了C++语言中友元函数的使用方法和应用场景,通过三个实例程序,详细说明了友元函数的声明、定义和使用。 知识点1:友元函数的声明和定义 在C++中,友元函数是指在类外部定义的函数,但可以访问类的...

    C ++友元函数的理解

    5. **谨慎使用**:虽然友元函数提供了灵活性,但过度使用可能会破坏封装性,使得代码更难以理解和维护。因此,应该谨慎地选择何时使用友元。 在给定的压缩包文件中,`二3.cpp`很可能是实现了上述Boat和Car类以及`...

    c++友元函数.doc

    c++友元函数.doc

    c++ demo,重载运算符,友元函数的实现

    在C++编程语言中,重载运算符和友元函数是两个重要的概念,它们扩展了C++的灵活性和表达能力。下面将详细讲解这两个主题及其在实际编程中的应用。 首先,我们来探讨重载运算符。重载运算符是指在同一个作用域内为一...

    友元函数和友元类_友元函数用法_

    标题"友元函数和友元类"涉及到两个核心概念:友元函数和友元类。 **友元函数** 是一个非成员函数,但它被声明为某个类的友元,这意味着它可以直接访问该类的私有和受保护成员。友元函数不是类的成员,因此它们不在...

    C++中普通函数声明为友元函数的练习之日期间隔

    ### C++中普通函数声明为友元函数的练习之日期间隔 #### 背景介绍 在面向对象编程中,类的设计与实现是至关...通过此类实践,初学者可以更好地理解C++中的类与对象的概念,以及如何灵活运用友元函数来扩展类的功能。

    Exe7_0友元_C++友元函数编程(两种有友元方式)_cloudzfv_

    本示例"Exe7_0友元_C++友元函数编程(两种有友元方式)_cloudzfv_"旨在帮助初学者理解并掌握C++中的友元函数的两种主要用法。现在,我们将详细讨论这两种友元函数的实现方式。 1. **友元函数** 友元函数不是类的...

    实例讲解C++友元,利用实例讲解C++友元的知识

    在这个实例讲解中,我们将深入理解C++友元的概念,并通过实际例子来阐述其应用。 一、友元的概念 友元不是类的成员,但它可以访问类的私有和保护成员。C++中的友元声明有两种形式:友元函数和友元类。友元函数是一...

    C++友元函数和友元类的学习心得[归纳].pdf

    C++友元函数和友元类的学习心得[归纳].pdf

    C++运算符重载友元函数实例

    在C++编程语言中,运算符重载是允许我们为已存在的运算符赋予新的含义或功能的一种机制。这个实例将探讨如何通过成员函数和非成员函数两种...通过练习和理解这些例子,你将更好地掌握C++中运算符重载和友元函数的使用。

    友元类,友元函数,友元成员函数

    在C++编程语言中,友元(Friend)是一种特殊的机制,允许类之间的访问权限超越默认的封装...通过阅读并理解提供的代码示例(如友元类.cpp、友元成员函数.cpp和友元函数.cpp),你可以更深入地了解这些概念的实际应用。

    c++模板友元函数 友元类

    关于c+模板之友元类友元函数的实例化,图形界面之矩形。

    友元函数详细讲解

    友元函数是C++语言中一个重要的概念,它突破了面向对象编程中类成员访问的封装性,允许某些外部函数或者类访问当前类的私有成员和保护成员。在实际开发中,合理使用友元函数可以优化代码结构,简化某些操作,但同时...

Global site tag (gtag.js) - Google Analytics