C++友元函数和友元类

简介:
如果类A希望类B可以访问它的私有成员,
可以把类B设置为友元类。
复制代码
//  类A,希望把私有成员公开给类B
class A
{
    friend  class B; //  把B设置为友元类
public:
    A( int i):m_i(i){}
private:
     int m_i;
     int getInt(){ return  100;}
};
//  类B,希望访问类A中的私有成员
class B
{
public:
    B(A a):m_a(a),m_n(a.m_i){}
     void setInt(){m_n = m_a.m_i;} // 访问私有变量
     int getInt(){ return m_a.getInt();}; // 访问私有函数
private:
     int m_n;
    A m_a;
};
void main()
{
    A a( 8);
    B b(a);
     int n = b.getInt();
}
复制代码
url: http://greatverve.cnblogs.com/archive/2012/11/22/cpp-friend.html  
参考一:

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

友元函数  
      友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字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修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员。
下面我们来看一段代码,看看我们是如何利用友元来访问类的一切成员的 

#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),这一点要注意。

一个普通函数可以是多个类的友元函数,对上面的代码我们进行修改,注意观察变化:
#include <iostream>
using namespace std;
class Country;
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,Country &cn);//注意这里
public:
    char name[20];
    char address[20];
};
class Country
{
public:
    Country()
    {
        strcpy(cname,"中国");
    }
    friend void ShowN(Internet &obj,Country &cn);//注意这里
protected:
    char cname[30];
};

void ShowN(Internet &obj,Country &cn)
{
    cout<<cn.cname<<"|"<<obj.name<<endl;
}
void main()
{
    Internet a("大气象","http://greatverve.cnblogs.com");
    Country b;
    ShowN(a,b);
    cin.get();
}

一个类的成员函数函数也可以是另一个类的友元,从而可以使得一个类的成员函数可以操作另一个类的数据成员,我们在下面的代码中增加一类Country,注意观察  
#include <iostream>
using namespace std;
class Internet;
class Country
{
public:
    Country()
    {
        strcpy(cname,"中国");
    }
    void Editurl(Internet &temp)               ;//成员函数的声明
protected:
    char cname[30];
};
class Internet
{
public:
    Internet(char *name,char *address)
    {
        strcpy(Internet::name,name);
        strcpy(Internet::address,address);
    }
    friend void Country::Editurl(Internet &temp); //友元函数的声明
protected:
    char name[20];
    char address[20];
};
void Country::Editurl(Internet &temp)        //成员函数的外部定义
{
    strcpy(temp.address,"edu.cndev-lab.com");
    cout<<temp.name<<"|"<<temp.address<<endl;
}
void main()
{
    Internet a("   大气象   ","   http://greatverve.cnblogs.com   ");
    Country b;
    b.Editurl(a);
    cin.get();
}

整个类也可以是另一个类的友元,该友元也可以称做为友类。友类的每个成员函数都可以访问另一个类的所有成员  
#include <iostream>
using namespace std;
class Internet;
class Country
{
public:
    Country()
    {
        strcpy(cname,"中国");
    }
    friend class Internet;             //友类的声明
protected:
    char cname[30];
};
class Internet
{
public:
    Internet(char *name,char *address)
    {
        strcpy(Internet::name,name);
        strcpy(Internet::address,address);
    }
    void Editcname(Country &temp);
protected:
    char name[20];
    char address[20];
};
void Internet::Editcname(Country &temp)
{
    strcpy(temp.cname,"中华人民共和国");
}
void main()
{
    Internet a("   大气象   ","   http://greatverve.cnblogs.com ");
    Country b;
    a.Editcname(b);
    cin.get();

} 



    本文转自wenglabs博客园博客,原文链接http://www.cnblogs.com/greatverve/archive/2012/11/22/cpp-friend.html:,如需转载请自行联系原作者



相关文章
|
10月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
6月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
162 0
|
6月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
255 0
|
8月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
298 12
|
9月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
178 16
|
9月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
9月前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
9月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
477 6
|
9月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
10月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)