【C++基础】友元总结一些坑

友元类

友元类(Friend Class)是一种在C++中用于实现类之间访问权限的特殊机制。通过友元类,一个类可以允许另一个类访问其私有成员,甚至可以使另一个类成为其友元,使其能够访问所有成员,包括私有成员这种机制可以用来增强两个类之间的灵活性和紧密性,但需要谨慎使用,以避免破坏封装性。

友元类的特点:

  • 友元类的声明位于类的定义中,使用friend关键字。

  • 友元类的成员函数可以访问该类的所有成员,包括私有成员。

  • 友元关系不能继承。如果类A是类B的友元,类B的派生类不会自动成为类A的友元。

  • 友元关系不是交换的,即如果类A是类B的友元,不一定意味着类B也是类A的友元。

1、声明一个类作为友元类

class FriendClass;  // 前向声明

class MyClass {
private:
    int privateData;

    friend class FriendClass;  // 声明FriendClass为友元类

public:
    MyClass(int data) : privateData(data) {}

    int getPrivateData() {
        return privateData;
    }
};

class FriendClass {
public:
    void accessPrivateData(MyClass& obj) {
        // 友元类可以访问MyClass的私有成员
        int data = obj.privateData;
        std::cout << "Accessed private data: " << data << std::endl;
    }
};

int main() {
    MyClass obj(42);
    FriendClass friendObj;
    friendObj.accessPrivateData(obj);  // 调用FriendClass的方法访问MyClass的私有成员

    return 0;
}

在上述示例中,FriendClass被声明为MyClass的友元类,因此FriendClass可以访问MyClass的私有成员privateData。注意,友元关系是单向的,所以MyClass不能直接访问FriendClass的私有成员。

需要注意的是,友元类机制可能会破坏类的封装性,因此应该谨慎使用。最好只在确实需要在类之间共享一些特定的访问权限时才使用友元类。

2、声明一个非类内函数作为友元函数

当我们需要将某个函数作为友元函数,而不是整个类时,可以通过在类中声明该函数为友元函数来实现。这样,该函数就可以访问类的私有成员。以下是一个示例:

class MyClass {
private:
    int privateData;

    // 声明友元函数
    friend void friendFunction(MyClass& obj);

public:
    MyClass(int data) : privateData(data) {}

    int getPrivateData() {
        return privateData;
    }
};

// 定义友元函数
void friendFunction(MyClass& obj) {
    int data = obj.privateData;
    std::cout << "Accessed private data from friend function: " << data << std::endl;
}

int main() {
    MyClass obj(42);
    friendFunction(obj);  // 调用友元函数访问MyClass的私有成员

    return 0;
}

在上述示例中,friendFunction被声明为MyClass的友元函数。这意味着friendFunction可以访问MyClass的私有成员。通过这种方式,我们可以在需要的情况下,将特定的函数授予对类私有成员的访问权限,而不需要将整个类作为友元。这样可以更加精细地控制访问权限,避免暴露不必要的细节。

3、友元底层实现机制

友元类和友元函数在底层实现上是编译器提供的一种特殊权限,允许某些类或函数访问其他类中的私有成员。它们的底层实现涉及访问权限和编译过程中的访问控制。

友元函数的底层实现:

当一个函数被声明为另一个类的友元函数时,编译器会在生成代码时为该友元函数提供对被访问类的私有成员的访问权限。这通常是通过在函数的调用处插入适当的访问代码来实现的。编译器会在友元函数的代码中直接访问被访问类的私有成员,无需经过任何访问权限检查。

友元类的底层实现:

当一个类被声明为另一个类的友元类时,编译器会在生成代码时为友元类提供对被访问类的私有成员的访问权限。这涉及到在友元类的定义中将访问权限扩展到被访问类的私有成员。编译器会在友元类的代码中直接访问被访问类的私有成员,同样无需经过访问权限检查。

编译器在生成代码时会根据友元关系插入适当的权限访问代码,以确保友元函数或友元类可以访问私有成员。这样,尽管在类的定义中进行了访问控制,但通过友元关系,某些函数或类可以绕过这些访问限制来访问私有成员。

总的来说,友元关系的底层实现是编译器在生成代码时做一些额外的处理,以允许友元函数或友元类访问其它类的私有成员。编译器会在生成的代码中插入适当的访问权限授予,从而避免了在编译时进行访问权限的检查。这使得在友元的作用下,私有成员可以在特定情况下被访问,同时也维护了类的封装性和隐私性。

4、类的前向声明

类的前向声明是一种在使用类之前声明该类的方法,从而在不必完全定义类的情况下使用它。前向声明可以在头文件中引入类的声明,而将类的具体实现留待在源文件中,这有助于减少编译时间和解除头文件的循环依赖。

具体来说,类的前向声明的作用包括:

  1. 解决循环依赖问题:当多个类相互依赖时,如果在头文件中直接包含对方的声明,可能会导致循环依赖,从而导致编译错误。使用前向声明可以避免这种问题。

  2. 提高编译效率:在头文件中只需要声明类的存在而不需要包含类的整个定义,可以减少编译时间。这对于大型项目和快速迭代的开发很有帮助。

  3. 隐藏实现细节:通过在头文件中只暴露类的接口,可以将类的实现细节封装在源文件中,提供更好的信息隐藏。

  4. 耦合:前向声明减少了类之间的直接依赖,从而使代码更加松散耦合,使得代码更易于维护和修改。

需要注意的是,前向声明只适用于指针和引用,因为在声明类时,编译器需要知道类的大小以及如何处理它的成员。如果需要使用类的成员或调用方法,就需要包含类的完整定义!!!!!

5、声明一个类内函数作为友元函数

有时,我们需要精细化的控制友元的范围,避免访问控制混乱,因此我们可以将某个类的其中一个函数声明为友元函数;

确实可以让特定的类成员成为另一个类的友元,而不必让整个类成为友元,但是这样做会稍微有点麻烦,必须小心排列各种声明和定义的顺序;

需要解决循环依赖问题,还需要了解前向声明到底是什么,可以利用前向声明访问什么

错误使用前向声明的demo

修改之后的

完整代码

#include <iostream>

class A; // 前向声明

class B {
  public:
    void callFriendFunction(A& a) {
        // 调用A的友元函数
        specificFunctionInB(a);
    }
    // 定义A的友元函数
    void specificFunctionInB(A& a);
};

class A {
  private:
    int privateA;

  public:
    A() : privateA(42) {}

    // 声明B的特定函数为友元函数
    friend void B::specificFunctionInB(A& a);
};

void B::specificFunctionInB(A& a) {
        std::cout << "Accessing A's privateA in B: " << a.privateA << std::endl;
}

int main() {
    A objA;
    B objB;

    objB.callFriendFunction(objA);
    return 0;
}

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

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

相关文章

python爬虫2:requests库-原理

python爬虫2&#xff1a;requests库-原理 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 目录结构 文章目录 python爬虫2&#xff1a;requests库-原理1. 概述2. re…

学习笔记-JVM-对象结构及生命周期

申明&#xff1a;文章内容是本人学习极客时间课程所写&#xff0c;文字和图片基本来源于课程资料&#xff0c;在某些地方会插入一点自己的理解&#xff0c;未用于商业用途&#xff0c;侵删。 原资料地址&#xff1a;课程资料 对象的创建流程 常量池检查:检查new指令是否能在常…

【设计模式——学习笔记】23种设计模式——中介者模式Observer(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入案例一普通实现中介者模式 案例二 介绍基础介绍登场角色尚硅谷 《图解设计模式》 案例实现案例一&#xff1a;智能家庭类图实现 案例二&#xff1a;登录页面逻辑实现说明类图实现 总结文章说明 案例引入 案例一 普通实现 在租房过程中&#xff0c;客户可能…

2.5D游戏是如何做出来的呢,2.5D游戏快速制作教程

前言 【Unity实战篇 】 | 如何制作一款2.5D游戏&#xff0c;2.5D游戏制作案例一、2.5D 游戏概念二、绘制地图三、添加玩家动画和移动等操作四、视角配置4.1 调整摄像机与场景对象的角度4.2 增加镜头旋转功能 五、游戏效果展示 总结 前言 玩过游戏的朋友都知道&#xff0c;市面…

HarmonyOS NEXT,生命之树初长成

在不同的神话体系中&#xff0c;都有着关于生命之树的记载。 比如在北欧神话中&#xff0c;一株巨大的树木联结着九大世界&#xff0c;其被称为“尤克特拉希尔”Yggdrasill。在中国的《山海经》中&#xff0c;也有着“建木”的传说&#xff0c;它“有九欘&#xff0c;下有九枸&…

idea添加翻译插件并配置有道翻译

1、安装Translation插件 2、 创建有道云应用 有道智云控制台 3、设置idea 4、效果&#xff08;选中文本右键翻译&#xff0c;默认快捷键CtrlShiftY&#xff09;

安达发制造工业迈向智能化:APS高级计划排程助力提升生产效率

随着市场竞争的加剧&#xff0c;制造企业纷纷寻求提高生产效率和降低成本的方法。近年来&#xff0c;越来越多的制造企业开始采用APS(高级计划与排程)系统&#xff0c;以优化生产计划和排程&#xff0c;提高生产效率&#xff0c;并在竞争中取得优势。 现代制造业通常面临复杂的…

Idea中maven无法下载源码

今天在解决问题的时候想要下载源码&#xff0c;突然发现idea无法下载&#xff0c;这是真的蛋疼&#xff0c;没办法查看原因&#xff0c;最后发现问题的原因居然是因为Maven&#xff0c;由于我使用的idea的内置的Bundle3的Maven&#xff0c;之前没有研究过本地安装和内置的区别&…

ESP 32 蓝牙虚拟键盘链接笔记本电脑的键值问题

由于打算利用esp32 通过蓝牙链接电脑后实现一些特俗的键盘功能&#xff0c;所以就折腾了一下&#xff0c;折腾最耗费时间的却是键值问题&#xff0c;让一个20多年的老司机重新补充了知识 过程曲折就不说了&#xff0c;直接说结果。 我们通过网络搜索获取的键值和蓝牙模拟键盘传…

Leetcode-每日一题【剑指 Offer 11. 旋转数组的最小数字】

题目 把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。 给你一个可能存在 重复 元素值的数组 numbers &#xff0c;它原来是一个升序排列的数组&#xff0c;并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如&#xff0c;数组 [3,4…

【论文阅读】对抗溯源图主机入侵检测系统的模仿攻击(NDSS-2023)

作者&#xff1a;伊利诺伊大学芝加哥分校-Akul Goyal、Gang Wang、Adam Bates&#xff1b;维克森林大学-Xueyuan Han、 引用&#xff1a;Goyal A, Han X, Wang G, et al. Sometimes, You Aren’t What You Do: Mimicry Attacks against Provenance Graph Host Intrusion Detect…

docker容器监控:Cadvisor +Prometheus+Grafana的安装部署

目录 Cadvisor PrometheusGrafana的安装部署 一、安装docker&#xff1a; 1、安装docker-ce 2、阿里云镜像加速器 3、下载组件镜像 4、创建自定义网络 二、部署Cadvisor 1、被监控主机上部署Cadvisor容器 2、访问cAdvisor页面 三、安装prometheus 1、部署Prometheus…

20230806将ASF格式的视频转换为MP4

20230806将ASF格式的视频转换为MP4 2023/8/6 18:47 缘起&#xff0c;自考中山大学的《计算机网络》&#xff0c;考试《数据库系统原理》的时候找到视频&#xff0c;由于个人的原因&#xff0c;使用字幕更加有学习效率&#xff01; 由于【重型】的PR2023占用资源较多&#xff0c…

Spring security之JWT

JWT 这里写目录标题 JWT一级目录二级目录三级目录1.什么是JWT 2.JWT的组成部分3.编码/解码4.特点5. 为什么使用JWT5.1传统的验证方式 5.2基于JWT的验证方式6.JWT进行登录验证6.1依赖安装6.2编写UserDetailServiceImpl类6.3编写UserDetailsImpl类6.4 实现config.SecurityConfig类…

算法与数据结构(二十二)动态规划解题套路框架

动态规划解题套路框架 此文只在个人总结 labuladong 动态规划框架&#xff0c;仅限于学习交流&#xff0c;版权归原作者所有&#xff1b; 动态规划问题&#xff08;Dynamic Programming&#xff09;应该是很多读者头疼的&#xff0c;不过这类问题也是最具有技巧性&#xff0c…

替换开源LDAP,某科技企业用宁盾目录统一身份,为业务敏捷提供支撑

客户介绍 某高科技企业成立于2015年&#xff0c;是一家深耕于大物流领域的人工智能公司&#xff0c;迄今为止已为全球16个国家和地区&#xff0c;120余家客户打造智能化升级体验&#xff0c;场景覆盖海陆空铁、工厂等货运物流领域。 该公司使用开源LDAP面临的挑战 挑战1 开源…

【用于全变分去噪的分裂布雷格曼方法】实施拆分布雷格曼方法进行总变异去噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

docker菜谱

DockerHub&#xff1a;https://hub.docker.com/ 记录docker常用软件安装&#xff0c;欢迎大家来投稿。&#x1f60e;&#x1f60e;&#x1f60e; 文章目录 1. Redis2. MariaDB 1. Redis dockerhub:https://hub.docker.com/_/redis 1、下载redis镜像&#xff1a; docker pull r…

【MFC】05.MFC第一大机制:程序启动机制-笔记

MFC程序开发所谓是非常简单&#xff0c;但是对于我们逆向人员来说&#xff0c;如果想要逆向MFC程序&#xff0c;那么我们就必须了解它背后的机制&#xff0c;这样我们才能够清晰地逆向出MFC程序&#xff0c;今天这篇文章就来带领大家了解MFC的第一大机制&#xff1a;程序启动机…

echarts 图表饼状图 实例

效果图&#xff1a; 代码&#xff1a; draw(data1, data2) {var option {// backgroundColor: rgb(10,36,68),color: [#F19611 ,#0095FE,#162D86,#0096FF,#05F8FF,#FFD985,#FACDAA,#F4A49E,#EE7B91,#E85285,#BE408C,#942D93,#171E6D,#1E3388,#27539B,#3073AE,#3993C2,#42B3D…