重学C++系列之友元

一、什么是友元

        在C++中,为了提高程序的效率,在一些场景下,引入友元,但同时类的封装性就会被破坏。

二、怎么实现友元

        友元关键字(friend)


// 在类中声明另一个类的成员函数来做为友元函数
// 以关键字(friend)开头:比如friend 返回值类型 类名::类成员函数(参数列表)
friend void A::test(Test &t);



// 全局函数做友元函数

// friend 普通函数的声明

friend void print(Test &t);


// 友元类,要在另外一个类中声明
class 类名1
{


    friend class 友元类名;    // 在类里面声明友元类
}

三、友元的特点

        1、友元关系是单向的,不具备交换性。

        2、友元关系不能被继承。

        3、友元关系不具有传递性。

        4、友元不是类成员,但是它可以通过对象访问类中私有成员,友元作用在于提高程序的运行效率,但是,它破坏了类的封装和数据隐藏性。除非调用访问私有成员变量的频率频繁,才会考虑牺牲封装和数据隐藏性,来换取运行效率。

        5、模板类中声明的友元函数必须要指定具体类型才行,不能声明一个友元函数模板。

四、案例

        1、 在类中声明另一个类的成员函数来做为友元函数

#include <iostream>

using namespace std;

class Base;
class Test
{
public:
    // 不可以在类中实现,只能在类外实现, 此时编译器还没有编译Base类,无法识别出友元
    void show(Base &other); 
    // {
    //     cout << "a = " << other.a << endl;
    // }

};

class Base
{
private:
    int a;
public:
    Base(int a = 0)
    {
        this->a = a;
    }
    friend void Test::show(Base &other);
};

// 不可以在类中实现,只能在类外实现,此时编译器已识别出友元
void Test::show(Base &other)
{
    cout <<"void Test::show(Base &other)" << endl;
    cout << "a = " << other.a << endl;
}


int main()
{

    Base A(10);
    Test test;
    test.show(A);


    return 0;
}

 

        2、全局函数做友元函数 

#include <iostream>

using namespace std;


class Base
{
private:
    int a;
public:
    Base(int a = 0)
    {
        this->a = a;
    }
    // 全局函数声明为友元函数
    friend void show(Base &other);
};

// 全局函数声明为友元函数
void show(Base &other)
{
    cout << "void show(Base &other)" << endl;
    cout << "a = " << other.a << endl;
}


int main()
{

    Base A(10);
    show(A);
   


    return 0;
}

        3、友元类

#include <iostream>

using namespace std;

class Test; // 先声明一个类Test

class Base
{
private:
    int a;
public:
    Base(int a = 0)
    {
        this->a = a;
    }
    friend class Test;  // 把类Test声明为友元类
};

class Test
{
public:
   
    void show(Base &other)
    {
        cout << "void Test::show(Base &other)" << endl;
        cout << "a = " << other.a << endl;
    }

};

int main()
{

    Base A(10);
    Test test;
    test.show(A);


    return 0;
}

        4、模板类中声明的友元函数必须要指定具体类型才行,不能声明一个友元函数模板。

#include <iostream>

using namespace std;



template <class T>
class Test
{
private:
    T a;
public:
    Test(T a = T())
    {
        this->a = a;
    }
    // 定义一个友元函数模板,编译不能通过
    friend ostream& operator << (ostream& output, const Test<T> &other);


};

template <class T>
ostream& operator << (ostream& output, const Test<T> &other)
{
    output << "a = " << other.a << endl;
    return output;
}



int main()
{
    Test<int> A(10);
    cout << A << endl;
    


    return 0;
}

        改正:

#include <iostream>

using namespace std;



template <class T>
class Test
{
private:
    T a;
public:
    Test(T a = T())
    {
        this->a = a;
    }
    // 指定友元函数的具体模板类型,但是这样模板类的作用几乎失效
    friend ostream& operator << (ostream& output, const Test<int> &other);


};

// 指定模板类为int类型
ostream& operator << (ostream& output, const Test<int> &other)
{
    output << "ostream& operator << (ostream& output, const Test<int> &other)" << endl;
    output << "a = " << other.a;
    return output;
}



int main()
{
    Test<int> A(10);
    cout << A << endl;
    


    return 0;
}

五、总结

        友元的作用是在某些场景提高程序的效率,但是同时也破坏了类的封装性和数据的隐藏性。声明友元时,要注意友元的位置,编译器是否已经识别或者编译了所声明的友元,如果没有,就会报错,所以可以采用再类中定义友元,把友元类的函数在类外实现,具体例子看上面的案例。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Centos部署Springboot项目详解

准备启动jar包&#xff0c;app.jar放入指定目录。 一、命令启动 1、启动命令 java -jar app.jar 2、后台运行 nohup java -jar app.jar >/dev/null 2>&1 & 加入配置参数命令 nohup java -Xms512M -Xmx512M -jar app.jar --server.port9080 spring.profiles…

基于鲸鱼优化算法的5G信道估计(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑…

Unity 工具之 NuGetForUnity 包管理器,方便在 Unity 中的进行包管理的简单使用

Unity 工具之 NuGetForUnity 包管理器&#xff0c;方便在 Unity 中的进行包管理的简单使用 目录 Unity 工具之 NuGetForUnity 包管理器&#xff0c;方便在 Unity 中的进行包管理的简单使用 一、简单介绍 二、NuGetForUnity 的下载导入 Unity 三、NuGetForUnity 在 Unity 的…

Jetbrains idea 代码关闭 注释自动渲染 导致换行不生效

方法1 关闭注释自动渲染 取消勾选 方法2 结尾使用 <br> 强制换行

vector使用

文章目录 vector的介绍vector的使用vector的初始化vector iterator迭代器的使用vector 空间增长问题vector的增删改查 迭代器失效总结 vector的介绍 文档介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着…

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境3

4、下载MaixPy IDE&#xff0c;MaixPy 使用Micropython 脚本语法&#xff0c;所以不像 C语言 一样需要编译&#xff0c;要使用MaixPy IDE , 开发板固件必须是V0.3.1 版本以上&#xff08;这里使用V0.5.0&#xff09;, 否则MaixPy IDE上会连接不上&#xff0c; 使用前尽量检查固…

宝塔设置云服务器mysql端口转发,实现本地电脑访问云mysql

环境&#xff1a;centos系统使用宝塔面板 实现功能&#xff1a;宝塔设置云服务器mysql端口转发&#xff0c;实现本地电脑访问mysql 1.安装mysql、PHP-7.4.33、phpMyAdmin 5.0 软件商店》搜索 mysql安装即可 软件商店》搜索 PHP安装7.4.33即可&#xff08;只需要勾选快速安装&…

iOS开发-实现快速登录弹窗与微信微博QQ三方登录切换控件

iOS开发-实现快速登录弹窗与微信微博QQ三方登录切换控件。 之前开发中实现快速登录弹窗与微信微博等了切换控件。 一、效果图 二、实现代码 实现背景渐变UIBlurEffect self.blurEffect [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; self.effectView [[UIVisu…

linux上适用的反汇编调试软件(对标od)

ubuntu下类似于od软件 经过搜索&#xff0c;在Ubuntu上选用edb-debugger进行动态调试&#xff0c; 下载链接: https://github.com/eteran/edb-debugger 但是依赖反汇编引擎: https://github.com/capstone-engine/capstone 安装 先安装capstone 先下载release的版本&#xf…

基于量子同态加密的安全多方凸包协议

摘要安全多方计算几何(SMCG)是安全多方计算的一个分支。该协议是为SMCG中安全的多方凸包计算而设计的。首先&#xff0c;提出了一种基于量子同态加密的安全双方值比较协议。由于量子同态加密的性质&#xff0c;该协议可以很好地保护量子电路执行过程中数据的安全性和各方之间的…

组合模式-树形结构的处理

A公司需要筛选出年龄35岁及以上(如果是领导&#xff0c;年龄为45岁及以上)的人。其组织架构图如下。 图 A公司部分组织架构图 图 传统解决方案 public class Development {private String name;public Development(String name) {this.name name;}List<Employee> emplo…

需求分析案例:消息配置中心

本文介绍了一个很常见的消息推送需求&#xff0c;在系统需要短信、微信、邮件之类的消息推送时&#xff0c;边界如何划分和如何设计技术方案。 1、需求 一个系统&#xff0c;一般会区分多个业务模块&#xff0c;并拆分成不同的业务系统&#xff0c;例如一个商城的架构如下&am…

flutter(01) windows桌面版 编译环境安装指南

1 flutter环境安装 flutter官网参考&#xff1a;Install | Flutter 先下载flutter SDK>&#xff1a;flutter sdk下载--官网&#xff0c;之后解压到C:\Users\XXX\data&#xff08;这里以该路径为例&#xff0c;但可以为其他自定义路径&#xff09;目录下&#xff0c;在这里…

栈和队列模拟实现(C++)

文章目录 0.码云完整代码1.deque的认识1.1介绍1.2图析1.3性能比较 2.stack的学习2.1模拟实现2.2测试函数 3.queue的学习3.1模拟实现3.2测试函数 4.优先级队列的学习4.0仿函数的引入4.1介绍4.2例题4.3模拟实现 5.测试函数 0.码云完整代码 点击 栈 队列 优先级队列 跳转码云获取…

鸿鹄协助管理华为云与炎凰Ichiban

炎凰对华为云的需求 在炎凰日常的开发中&#xff0c;对于服务器上的需求&#xff0c;我们基本都是采用云服务。目前我们主要选择的是华为云&#xff0c;华为云的云主机比较稳定&#xff0c;提供的云主机配置也比较多样&#xff0c;非常适合对于不同场景硬件配置的需求&#xff…

石子合并(区间dp模板)

题目描述&#xff1a; dp分析&#xff1a; 解题代码&#xff1a; #include<iostream> using namespace std;const int N1e36;int f[N][N]; int a[N]; int s[N];int main(){int n;cin>>n;for(int i1;i<n;i){scanf("%d",&s[i]);s[i]s[i-1];//前缀和…

2.1数据结构——线性表

一、定义 线性表是具有相同数据类型的n&#xff08;n>0&#xff09;个数据元素的有限序列&#xff0c;&#xff08;n表示表长&#xff0c;n0为空表&#xff09; 用L表示&#xff1a; 位序&#xff1a;线性表中的“第i个” a1是表头元素&#xff1b;an是表尾元素 除第一个…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(8)-Fiddler如何设置捕获会话

1.简介 前边几篇宏哥介绍了Fiddler界面内容以及作用。今天宏哥就讲解和分享如何设置Fiddler后&#xff0c;我们就可以捕获会话&#xff0c;进行抓包了。 2.捕获会话的设备 常见的捕获会话的设备分为PC&#xff08;电脑&#xff09;端和手机&#xff08;Android和IOS苹果&…

【SpringⅢ】Spring 的生命周期

目录 &#x1f96a;1 Bean 的作用域 &#x1f969;1.1 singleton&#xff1a;单例模式 &#x1f359;1.2 prototype&#xff1a;原型模式 &#x1f371;1.3 Bean 的其他作用域 &#x1f35c;2 Spring 生命周期(执行流程) &#x1f958;2.1 启动容器 &#x1f372; 2.2 读…

Elasticsearch:使用 ELSER 释放语义搜索的力量:Elastic Learned Sparse EncoderR

问题陈述 在信息过载的时代&#xff0c;根据上下文含义和用户意图而不是精确的关键字匹配来查找相关搜索结果已成为一项重大挑战。 传统的搜索引擎通常无法理解用户查询的语义上下文&#xff0c;从而导致相关性较低的结果。 解决方案&#xff1a;ELSER Elastic 通过其检索模型…