C++中友元概念

news2024/9/24 4:21:41

目录

前言

一、友元函数

 二、友元类

 三、友元成员函数

 总结


前言

        在类创建对象,类的成员存在权限,默认有些成员不能在类外进行访问,但是有特定情况想要访问对象的私有成员,允许一种特殊的访问方式(在类外也可以访问到对象的私有成员),叫做友元访问,如何能够实现友元访问功能呢,一般我们通过友元函数,友元类,或则友元成员函数来实现,通过友元访问,能够无视privateprotected,直接能够访问到不能类外访问的属性,下面我们将来分开描述各种友元来访问类中的属性的实现,以及修改类中值的操作

一、友元函数

        友元函数(friend function)是C++中一种特殊的函数,它可以访问类的私有成员(private)和保护成员(protected),即使它本身不是该类的成员函数。在C++中,类通常封装了数据,使用privateprotected访问控制来保护类的内部成员变量和函数。但有时需要让外部函数或其它类能够访问这些私有成员。此时,友元函数可以实现这一目的。

        友元函数虽然能访问类的私有和保护成员,但它并不属于类的成员函数,不能通过类的对象调用它,调用时使用普通的函数调用方式。

        友元函数虽然使得外部函数可以访问类的私有成员,但它也打破了类的封装性。因此,在设计时要谨慎使用友元函数,不要滥用它。


#include <iostream>

class Animal {
    private:
        int age;        // 动物的年龄
        double weight;  // 动物的体重
    public:
        // 构造函数
        Animal(int a, double w) : age(a), weight(w) {}

        // 友元函数声明
        friend void showAnimalDetails(const Animal& animal);

        // 成员函数:动物的行为
        void eat() const {
            std::cout << "The animal is eating." << std::endl;
        }

        void sleep() const {
            std::cout << "The animal is sleeping." << std::endl;
        }
};

// 友元函数定义
void showAnimalDetails(const Animal& animal) {
    // 友元函数可以访问类的私有成员
    std::cout << "Animal Details:" << std::endl;
    std::cout << "Age: " << animal.age << " years" << std::endl;
    std::cout << "Weight: " << animal.weight << " kg" << std::endl;
}

int main() {
    // 创建一个 Animal 对象
    Animal lion(5, 190.5);

    // 调用友元函数,显示动物的详细信息
    showAnimalDetails(lion);

    // 调用动物的行为函数
    lion.eat();
    lion.sleep();

    return 0;
}

 二、友元类

        友元类是指一个类将另一个类声明为友元类,允许该友元类访问它的私有和保护成员。整个友元类中的所有成员函数都可以访问另一个类的私有成员,在下面的代码当中所示:

#include <iostream>

// 前向声明类 Dog
class Dog;

class Animal {
    private:
        int age;        // 动物的年龄
        double weight;  // 动物的体重
    public:
        // 构造函数
        Animal(int a, double w) : age(a), weight(w) {}

        // 将 Dog 类声明为友元类
        friend class Dog;
};

// Dog 类定义
class Dog {
    public:
        void showAnimalDetails(const Animal& animal) const {
            // 作为友元类,Dog 可以访问 Animal 的私有成员
            std::cout << "Animal Details (from Dog):" << std::endl;
            std::cout << "Age: " << animal.age << " years" << std::endl;
            std::cout << "Weight: " << animal.weight << " kg" << std::endl;
        }

        void bark() const {
            std::cout << "The dog is barking." << std::endl;
        }

        void wagTail() const {
            std::cout << "The dog is wagging its tail." << std::endl;
        }
};

int main() {
    // 创建一个 Animal 对象
    Animal lion(5, 190.5);

    // 创建一个 Dog 对象
    Dog myDog;

    // Dog 对象调用其成员函数,显示 Animal 对象的详细信息
    myDog.showAnimalDetails(lion);

    // 调用 Dog 对象的行为函数
    myDog.bark();
    myDog.wagTail();

    return 0;
}

        在这个代码当中,我们将狗这个类用friend标识,标识狗这个类是动物这个类的友元类,狗这个类中的对象可以直接使用动物这个类当中的函数,并且还能访问其私有成员变量。

 三、友元成员函数

        友元成员函数是指一个类的某个成员函数被另一个类声明为友元。这样,只有该成员函数有权限访问该类的私有和保护成员,而不是整个类。

#include <iostream>

// 前向声明类 Dog
class Dog;

class Animal {
    private:
        int age;        // 动物的年龄
        double weight;  // 动物的体重
    public:
        // 构造函数
        Animal(int a, double w) : age(a), weight(w) {}

        // 将 Dog 类的 showAnimalDetails 成员函数声明为友元函数
        friend void Dog::showAnimalDetails(const Animal& animal);
};

// Dog 类定义
class Dog {
    public:
        void showAnimalDetails(const Animal& animal) const {
            // 作为友元成员函数,showAnimalDetails 可以访问 Animal 的私有成员
            std::cout << "Animal Details (from Dog's member function):" << std::endl;
            std::cout << "Age: " << animal.age << " years" << std::endl;
            std::cout << "Weight: " << animal.weight << " kg" << std::endl;
        }

        void bark() const {
            std::cout << "The dog is barking." << std::endl;
        }

        void wagTail() const {
            std::cout << "The dog is wagging its tail." << std::endl;
        }
};

int main() {
    // 创建一个 Animal 对象
    Animal lion(5, 190.5);

    // 创建一个 Dog 对象
    Dog myDog;

    // 使用 Dog 对象调用 showAnimalDetails 函数,显示 Animal 对象的详细信息
    myDog.showAnimalDetails(lion);

    // 调用 Dog 对象的行为函数
    myDog.bark();
    myDog.wagTail();

    return 0;
}

        看上面的代码,我们只是将狗类中的成员函数给用friend进行了标识,表示只有这个成员函数能够访问动物类中的成员,而不是整个狗类都能访问动物类中的成员。

 总结

        友元访问提供了一种便利,当我们不能直接访问其他类中的私有成员时,可以设置友元来进行访问,并且还能通过友元来将其他类中的成员值进行修改;如下:

#include <iostream>

// 前向声明类 Dog
class Dog;

class Animal {
    private:
        int age;        // 动物的年龄
        double weight;  // 动物的体重
    public:
        // 构造函数
        Animal(int a, double w) : age(a), weight(w) {}

        // 将 Dog 类的 modifyAnimalDetails 成员函数声明为友元函数
        friend void Dog::modifyAnimalDetails(Animal& animal, int newAge, double newWeight);
        
        // 成员函数:显示动物的详细信息
        void showDetails() const {
            std::cout << "Animal Details:" << std::endl;
            std::cout << "Age: " << age << " years" << std::endl;
            std::cout << "Weight: " << weight << " kg" << std::endl;
        }
};

// Dog 类定义
class Dog {
    public:
        void modifyAnimalDetails(Animal& animal, int newAge, double newWeight) const {
            // 作为友元成员函数,modifyAnimalDetails 可以修改 Animal 的私有成员
            animal.age = newAge;
            animal.weight = newWeight;
        }

        void bark() const {
            std::cout << "The dog is barking." << std::endl;
        }

        void wagTail() const {
            std::cout << "The dog is wagging its tail." << std::endl;
        }
};

int main() {
    // 创建一个 Animal 对象
    Animal lion(5, 190.5);
    
    // 显示 Animal 对象的初始详细信息
    std::cout << "Initial ";
    lion.showDetails();

    // 创建一个 Dog 对象
    Dog myDog;

    // 使用 Dog 对象调用 modifyAnimalDetails 函数来修改 Animal 对象的详细信息
    myDog.modifyAnimalDetails(lion, 7, 210.0);

    // 显示 Animal 对象的修改后的详细信息
    std::cout << "After modification by Dog: ";
    lion.showDetails();

    // 调用 Dog 对象的行为函数
    myDog.bark();
    myDog.wagTail();

    return 0;
}

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

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

相关文章

Netty笔记07-粘包与半包(上)

文章目录 前言1. 粘包造成粘包的原因解决粘包的方法 2. 半包造成半包的原因解决半包的方法 粘包现象服务端代码示例客户端代码示例 半包现象现象分析粘包半包滑动窗口MSS 限制Nagle 算法 前言 粘包和半包问题是网络编程中常见的问题&#xff0c;特别是在TCP协议中。通过合理的设…

C++编程语言:基础设施:源文件和程序(Bjarne Stroustrup)

第15章 源文件和程序 (Source Files and Programs) 目录 15.1 单独编译(Separate Compilation) 15.2 链接(Linkage) 15.2.1 文件局部名(File-Local Names) 15.2.2 头文件(Header Files) 15.2.3 一次定义原则(The One-Definition Rule) 15.2.4 标准库头文件 1…

Python办公自动化教程(001):PDF内容提取

1、Pdfplumber介绍 pdfplumber的github地址&#xff1a; https://github.com/jsvine/pdfplumber/【介绍】&#xff1a;pdfplumber 是一个用于处理 PDF 文件的 Python 第三方库&#xff0c;它提供了一种方便的方式来提取 PDF 文件中的文本、表格和其他信息。【功能】&#xff…

JEDEC DDR3 SRAM standard

DDRDouble Data Rate双倍速率,DDR SDRAM双倍速率同步动态随机存储器&#xff0c;人们习惯称为DDR&#xff0c;其中&#xff0c;SDRAM 是Synchronous Dynamic Random Access Memory的缩写&#xff0c;即同步动态随机存取存储器。而DDR SDRAM是Double Data Rate SDRAM的缩写&…

交叉熵损失函数的使用

交叉熵损失函数 交叉熵损失函数&#xff08;Cross-Entropy Loss&#xff09;&#xff0c;也称为对数损失&#xff08;Log Loss&#xff09;&#xff0c;是机器学习和深度学习中常用的损失函数之一&#xff0c;尤其在分类问题中。它衡量的是模型预测的概率分布与真实标签的概率…

写作文的AI,不妨试试这些工具

写作文的AI&#xff0c;随着人工智能技术的迅猛发展&#xff0c;AI写作软件已经成为许多作家、学生和内容创作者的得力助手。这些软件不仅能帮助用户生成高质量的文章&#xff0c;还能提供创意灵感、语法校正和内容优化等多重功能。下面&#xff0c;本文将介绍五款各具特色的AI…

s3c2440——UART串口通信

一、通信方式 1、并行通信&#xff1a;一次可收发2bit/2bit以上。通信效率高&#xff1b;但对SOC硬件资源占用率太高。 串行通信&#xff1a;一次通信传递1bit。降低对硬件占用率&#xff1b;但通信速率低。 2、单工通信&#xff1a;只能A发送&#xff0c;B接收。 半双工通信…

D. Minimize the Difference (Codeforces Round 973 Div. 2)

D. Minimize the Difference 思路&#xff1a; 发现操作是单向的从左往右取高补低&#xff0c;最终目标是尽可能趋于平均&#xff0c;使最大值最小和使最小值最大。可以用二分答案法分别找到两个最值&#xff0c;然后做差即可。 关于这种算法的正确性没有做严格的证明&#x…

国庆节适合买什么东西?精选五款实用又优惠的多功能好物!

临近国庆&#xff0c;我猜很多朋友已经开始为假期做好准备&#xff0c;计划开启出游和购物的节奏了&#xff01;大家都希望在国庆期间&#xff0c;买到一些平时因为价格太贵而舍不得下单的好物&#xff01;作为一名家居兼数码博主&#xff0c;每年国庆的时候我都会疯狂采购各种…

那年我双手插兜,使用IPv6+DDNS动态域名解析访问NAS

估计有很多科技宅和我一样&#xff0c;会买一个NAS存储或者自己折腾刷一下黑群晖玩玩&#xff0c;由于运营商不给分配固定的公网IP&#xff0c;就导致我在外出的时候无法访问家里的NAS&#xff0c;于是远程访问常常受到IP地址频繁变动的困扰。为了解决这一问题&#xff0c;结合…

对FPGA加载过程中不同寄存器初始化方式现象的分析

对FPGA加载过程中不同寄存器初始化方式现象的分析 概述目的术语和缩略语参考资料 相关原理分析MMCM时钟锁定分析声明信号时进行初始化RTL测试代码示波器现象 同步复位/置位初始化RTL测试代码示波器现象 异步复位/置位初始化RTL测试代码示波器现象 不进行任何初始化操作&#xf…

JSP 指令标识和脚本标识的使用

文章目录 前言一、JSP 页面是什么&#xff1f;二、JSP 基本语法 1.指令标识 &#xff08;1&#xff09;page 指令&#xff08;2&#xff09;include 指令&#xff08;3&#xff09;taglib 指令2.脚本标识总结 前言 在进行Java Web 应用开发的过程中&#xff0c;JSP 是必不可少的…

9.19工作笔记

怎么做多空对冲 脚本2 read_coin选币单币涨跌幅计算单币资金曲线单币资金曲线均值得到周期总体资金曲线周期总体资金曲线得到周期总体涨跌幅周期总体涨跌幅计算得到总体资金曲线 脚本2怎么实现多空对冲的 首先读取factors和periods中的文件&#xff0c;然后read_coin得到结…

Proteus-7.8sp2安装

一、D盘新建空文件夹&#xff0c;名为Proteus。 二、安装软件 1.双击P7.8sp2.exe 2.next 三、破解 1.双击 Proteus Pro 7.8 SP2破解 1.0.exe 2. 升级 打开软件 四、汉化 1.将如下两个文件复制到 D:\Proteus\BIN 路径中 重新打开软件&#xff0c;汉化成功

【在.net6和WPF框架下进行海康SDK开发】(一)如何引用Dll

最近有个上位机项目&#xff0c;需要将海康VisionMaster的部分功能嵌入到统一的界面。项目使用WPFdotNet6开发&#xff0c;UI库使用HandyControl。 先说下需求&#xff0c;在某个TabItem内嵌入一个UserControl&#xff0c;UserContr内嵌入VisionMaster运行界面。 本以为按照海康…

10年计算机考研408-计算机网络

【题33】下列选项中&#xff0c;不属于网络体系结构所描述的内容是&#xff08;&#xff09; A.网络的层次 B.每一层使用的协议 C.协议的内部实现细节 D.每一层必须完成的功能 解析&#xff1a; 本题考查的是网络体系结构相关的概念。 图1描述了网络的7层架构以及每一层所要完成…

智能新突破:AIOT 边缘计算网关让老旧水电表图像识别

数字化高速发展的时代&#xff0c;AIOT&#xff08;人工智能物联网&#xff09;技术正以惊人的速度改变着我们的生活和工作方式。而其中&#xff0c;AIOT 边缘计算网关凭借其强大的功能&#xff0c;成为了推动物联网发展的关键力量。 这款边缘计算网关拥有令人瞩目的 1T POS 算…

某文书网爬虫逆向

一、抓包分析 请求参数和响应数据都有加密 二、逆向分析 老方法、下xhr断点 加密实现逻辑都在这个方法里 执行到这的时候&#xff0c;在向下跟栈数据就已经渲染出来了&#xff0c;说明是在这个方法里进行的解密 解密方法&#xff0c;data.result为加密数据&#xff0c;data.s…

Plant Disease Expert:植物病害数据集(猫脸码客 第197期)

Plant Disease Expert 数据集详细介绍 一、引言 在农业生产的广阔领域中&#xff0c;植物病害始终是一个不可忽视的挑战。它不仅直接威胁到作物的健康生长&#xff0c;还可能导致严重的产量下降&#xff0c;进而影响全球粮食安全和农业经济稳定。据权威机构估计&#xff0c;全…

18 基于51单片机的心率体温监测报警系统(包括程序、仿真、原理图、流程图)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机 ds18B20读取温度&#xff0c; 设置初始心率65 设置温度阈值38 心率阈值60 100 如果超过阈值&#xff0c;蜂鸣器报警&#xff0c;led灯亮 二、硬件资源 基于KEIL5编写C代码&#xf…