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

news2025/7/10 20:16:38

友元类

友元类(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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[HDLBits] Exams/m2014 q4f

Implement the following circuit: module top_module (input in1,input in2,output out);assign out (!in2)&in1; endmodule

gma 2 教程(二)数据操作:5. 多维科学数据

多维科学数据定义 如下图所示&#xff0c;gma将多维栅格定义为N&#xff08;>1&#xff09;个普通栅格数据集&#xff08;DataSet&#xff09;1组&#xff08;记录多维数据信息的&#xff09;元数据组成的多数据集&#xff08;MultiDataSets&#xff09;。   注&#xff1…

Leetcode.2146 价格范围内最高排名的 K 样物品

题目链接 Leetcode.2146 价格范围内最高排名的 K 样物品 rating : 1837 题目描述 给你一个下标从 0 0 0 开始的二维整数数组 g r i d grid grid &#xff0c;它的大小为 m x n &#xff0c;表示一个商店中物品的分布图。数组中的整数含义为&#xff1a; 0 表示无法穿越的一…

伪原创小发猫怎么样【php源码】

大家好&#xff0c;小编为大家解答初学者自学python哪本书好的问题。很多人还不知道自学python需要什么基础&#xff0c;现在让我们一起来看看吧&#xff01; 火车头采集ai伪原创插件截图&#xff1a; 目前python可以说是一门非常火爆的编程语言&#xff0c;应用范围也非常的广…

TCP三次握手、四次握手过程,以及原因分析

TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手&#xff1a;为了对每次发送的数据量进行跟踪与协商&#xff0c;确保数据段的发送和接收同步&#xff0c;根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系&#xff0c;并建立虚连接。 四次挥手&…

vs code remote ssh: Resolver error: Error: Got bad result from install script

今天像往常一样&#xff0c;打开 windows 11&#xff0c;使用 vs code 远程连接服务器 ubuntu 20&#xff0c;但是遇到了一个错误&#xff1a;Resolver error: Error: Got bad result from install script。 ok&#xff01;&#xff01;&#xff01;开始 Bing &#xff01;&…

.Net C# 免费PDF合成软件

最近用到pdf合成&#xff0c;发现各种软件均收费啊&#xff0c;这个技术非常简单&#xff0c;别人写好的库一大把&#xff0c;这里用到了PDFsharp&#xff0c;项目地址Home of PDFsharp and MigraDoc Foundation 软件下载地址 https://download.csdn.net/download/g313105910…

OBD针脚定义参考

OBD定义的一种标准的参考&#xff0c;不同的车场有不同的定义&#xff0c;貌似没有统一。 在某宝上看到的ODB转db9的不同的线序&#xff1a; 1&#xff09;1/2/3/6几个针脚都是一样的&#xff0c;分别上下针脚对应。 2&#xff09;其中一种4/5/7/8也是上下对应的&#xff1b;另…

检验代码生成器完成版

写维护页面重复逻辑写烦了&#xff0c;连页面的增、删、改、查、弹窗等代码都不行手写了&#xff0c;为此做成代码生成器成型版1.0.干到10点。。。 代码&#xff1a; Class Demo.CodeGener Extends %RegisteredObject {/// 生成操作表相关的代码&#xff0c;包括M、C#调用代码…

有效管理IT问题的5个原则

问题管理就是发现未知的、隐藏的问题&#xff0c;这是根本原因&#xff0c; 这是您 IT 帮助台无穷无尽的工单来源。当您实施有效的 问题管理&#xff0c;您的 IT 团队可以超越消防模式&#xff0c;专注于战略 IT 目标。以下是可以帮助您实现一流问题管理的五个原则&#xff1a;…

远程运维大批量IT设备?向日葵批量部署、分组授权与安全功能解析

数字化转型的不断推进&#xff0c;给予了企业全方位的赋能&#xff0c;但任何发展都伴随着成本与代价&#xff0c;比如在数字化转型过程中企业内部办公与外部业务所需的不断增加的IT设备数量&#xff0c;就为日常的运维工作提出了更大的挑战。 针对企业面对海量IT设备时的运维…

多态总结

什么是多态&#xff1f; 所谓多态&#xff0c;就是同一个操作&#xff0c;作用在了不同的对象上&#xff0c;就会有不同的解释&#xff0c;进而产生不同的执行结果。使用时&#xff0c;是采用父类指针指向子类对象的方法。其中&#xff0c;重载和重写是常见的实现多态的手段。…

【MySQL】基础知识(一)

MySQL基础知识&#xff08;一&#xff09; 文章目录 MySQL基础知识&#xff08;一&#xff09;00 MySQL安装01 数据库介绍1.1 什么是数据库1.2数据库分类 02 SQL分类03 数据库操作3.1显示数据库3.2创建数据库3.3选中数据库3.4删除数据库 04 常用数据类型4.1数值类型4.2字符串类…

LeetCode 0024. 两两交换链表中的节点:粗暴易懂的方法(几个临时变量)

【LetMeFly】24.两两交换链表中的节点&#xff1a;粗暴易懂的方法&#xff08;几个临时变量&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/swap-nodes-in-pairs/ 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点…

安路FPGA的赋值报错——移位处理,加括号

authordaisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 在使用移位符号用来当作除以号使用时&#xff0c;发现如下问题 其中 cnt_8K 为偶数和奇数时输出的数据不一样 reg [10:0] cnt_8K; reg [10:0] ram1_addra; always(posedge clk_16M) begin if(ram_out_flag )begin if(…

2023年新手如何学剪辑视频 想学视频剪辑如何入门

随着短视频、vlog等媒体形式的兴起&#xff0c;视频剪辑已经成为了热门技能。甚至有人说&#xff0c;不会修图可以&#xff0c;但不能不会剪视频。实际上&#xff0c;随着各种智能软件的发展&#xff0c;视频剪辑已经变得越来越简单。接下来&#xff0c;一起来看看新手如何学剪…

重磅来袭!Android UI设计规范助你打造精美Android应用!

重磅来袭&#xff01;Android UI设计规范助你打造精美Android应用&#xff01; 为了规范Android UI设计&#xff0c;Google官方推出UI设计指南助你打造精美的Android应用。 使用 Android 主题和组件创建应用设计。利用 Android 独特的设计模式和产品打造精美、易用的现代应用…

nginx之location匹配的规则和优先级,以及rewrite

主要内容&#xff1a;一、location匹配的规则和优先级&#xff08;重点&#xff0c;面试会问&#xff0c;工作用得到&#xff09; 二、nginx常用的问题&#xff08;要求掌握&#xff09; 三、rewrite&#xff1a;重定向功能&#xff08;有掌握&#xff0c;有理解&#xff09;…

DNS:使用 bind9 配置主从权威DNS服务器

写在前面 分享一些 使用 bind9 配置主从权威名称服务器的笔记理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整的&#xff0c;是人的逃避方式…

设计模式行为型——策略模式

在现实生活中常常遇到达成某种目的&#xff0c;有多种实现策略可供选择的情况。例如&#xff0c;出行上班可以乘坐公交车、乘坐地铁、骑自行车或自己开私家车等&#xff0c;填饱肚子可以吃火锅、吃烤肉、吃烤串、吃东北家常菜等方法。 在软件开发中也常常遇到类似的情况&#x…