云南建站/seo自动优化工具

云南建站,seo自动优化工具,做跨境电商有没推荐的网站,做货代在哪个网站找客源这几天在复习数学考试,都没有学C,今天抽空来学一点。 什么是友元? 友元是C中的一种关系友元发生在函数与类之间或者类与类之间友元关系是单向的,不能传递 在具体讲解友元的性质之前,我们先来看看一个程序&#xff…

这几天在复习数学考试,都没有学C++,今天抽空来学一点。

什么是友元?

  • 友元是C++中的一种关系
  • 友元发生在函数与类之间或者类与类之间
  • 友元关系是单向的,不能传递
    这里写图片描述

在具体讲解友元的性质之前,我们先来看看一个程序,这个程序是计算两点之间的距离:

#include <stdio.h>
#include <math.h>class Point
{
private:double x;double y;
public:Point(double x,double y){this->x = x; //this指针指向当前的对象this->y = y;}double getX(){return x;}double getY(){return y;}
};double func(Point& p1,Point& p2)
{double ret = 0;ret = (p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) +(p1.getY() - p2.getY()) * (p1.getY() - p2.getY());ret = sqrt(ret);return ret;
}int main()
{Point p1(1,2);Point p2(10,20);printf("p1(%f,%f)\n",p1.getX(),p1.getY());printf("p2(%f,%f)\n",p2.getX(),p2.getY());printf("|p1-p2| = %f\n",func(p1,p2));return 0;
}

上面代码运行结果为:

p1(1.000000,2.000000)
p2(10.000000,20.000000)
|p1-p2| = 20.124612

看着也没什么大问题。下面我们来简单分析一下这个程序的实用性:进行计算这个两点之间的距离时的代码为:

 ret = (p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) +(p1.getY() - p2.getY()) * (p1.getY() - p2.getY());

进行了8次函数的调用!!!这么简单的计算,就需要调用8次函数,这效率之慢在当初C++诞生的时候,是不被大多数人接受的,大多数人用C编程习惯了,都是可以直接这样调用的:

 ret = (p1.x - p2.x) * (p1.x - p2.x) +(p1.y - p2.y) * (p1.y - p2.y);

然而C++里面你就不能像上面那样直接调用类(C里面可以是结构体或者数组)的成员变量。因为它是private类型的变量。那么在C++诞生的那个年代,人们为了让C++语言完全兼容C语言,就在C++中加入了友元的存在。那么友元的定义以及性质是什么样的呢?

  • 在类中以friend关键字声明友元
  • 类的友元可以是其他类或者具体的函数
  • 友元不是类的一部分
  • 友元不受类中访问级别的限制
  • 友元可以直接访问具体类的所有成员

直接将上面的代码修改一下看看:

#include <stdio.h>
#include <math.h>class Point
{
private:double x;double y;
public:Point(double x,double y){this->x = x; //this指针指向当前的对象this->y = y;}double getX(){return x;}double getY(){return y;}friend double func(Point& p1,Point& p2)};double func(Point& p1,Point& p2)
{double ret = 0;ret = (p1.x - p2.x) * (p1.x - p2.x) +(p1.y - p2.y) * (p1.y - p2.y);ret = sqrt(ret);return ret;
}int main()
{Point p1(1,2);Point p2(10,20);printf("p1(%f,%f)\n",p1.getX(),p1.getY());printf("p2(%f,%f)\n",p2.getX(),p2.getY());printf("|p1-p2| = %f\n",func(p1,p2));return 0;
}

运行结果为:

p1(1.000000,2.000000)
p2(10.000000,20.000000)
|p1-p2| = 20.124612

这样看来,我们已经实现了直接访问类的私有成员变量。上面的代码,func函数是Point类的友元,可以直接访问Point的所有数据。但是这样做,又不好,为什么呢?
友元的尴尬:

  • 友元是为了兼顾C语言的高效性而诞生的
  • 友元直接破坏了面向对象的封装性
  • 友元在实际产品中的高效是得不偿失的
  • 友元在现代软件工程中已经被逐渐遗弃

虽然基于以上的尴尬让友元这个功能在现代软件工程中很少被使用,但是我们学习嘛,肯定是都要学的,哈哈~

友元需要注意的一些事项:

  • 友元关系不具备传递性
  • 类的友元可以是其他类的成员函数
  • 类的友元可以是某个完整的类(所有的成员函数都是友元)
    这里写图片描述
    下面我们再分析一个代码,来看看友元的真实面目:
#include <stdio.h>class ClassC
{const char* n;
public:ClassC(const char* n){this->n = n;}friend class ClassB;
};class ClassB
{const char* n;
public:ClassB(const char* n){this->n = n;}void getClassCName(ClassC& c){printf("c.n = %s\n", c.n);}friend class ClassA;
};class ClassA
{const char* n;
public:ClassA(const char* n){this->n = n;}void getClassBName(ClassB& b){printf("b.n = %s\n", b.n);}/*void getClassCName(ClassC& c){printf("c.n = %s\n", c.n);}*/
};int main()
{ClassA A("A");ClassB B("B");ClassC C("C");A.getClassBName(B);B.getClassCName(C);return 0;
}

运行结果为:

b.n = B
c.n = C

分析代码知:类B是C的友元,类A是B的友元,所以在B中可以直接访问C的私有成员变量,在A中可以直接访问B的成员变量。 那么在A中能否直接访问C呢?试验一下将上面的代码注释掉得部分恢复,编译运行,运行结果为:

test.cpp: In member function ‘void ClassA::getClassCName(ClassC&)’:
test.cpp:6: error: ‘const char* ClassC::n’ is private
test.cpp:44: error: within this context

很显然,A是不能访问C的私有成员的。

总结一下:

  • 友元是为了兼顾C语言的高效而诞生的
  • 友元直接破坏了面向对象的封装性
  • 友元关系不具备传递性
  • 类的友元可以是其他类的成员函数
  • 类的友元可以是某个完整的类
    这里写图片描述

想获得各种学习资源以及交流学习的加我(有我博客中写的代码的原稿):
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题。

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

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

相关文章

call stack and stack buffer overflow

http://en.wikipedia.org/wiki/Call_stack http://en.wikipedia.org/wiki/Stack_buffer_overflow Stack_buffer_overflow里提到的frame pointer 的位置不一样&#xff0c;不同的系统实现应该是不一样的。 运行时的栈是从高地址向低地址分配的&#xff0c;堆是从低地址向高地址…

【C++深度剖析教程8】C++的操作符重载的概念

之前学习了类的函数重载的概念&#xff0c;今天学习操作符重载的概念。在这之前我们先看一个例子&#xff1a; 上面是一个复数的加法&#xff0c;a为复数的实部&#xff0c;b为复数的虚部&#xff0c;在main函数里我想实现复数c1与c2的加法。很显然&#xff0c;正常的号操作符…

大数据开发者应该知道的分布式系统 CAP 理论

无论你是一个系统架构师&#xff0c;还是一个普通开发&#xff0c;当你开发或者设计一个分布式系统的时候&#xff0c;CAP理论是无论如何也绕不过去的。本文就来介绍一下到底什么是CAP理论&#xff0c;如何证明CAP理论&#xff0c;以及CAP的权衡问题。 CAP理论概述 CAP理论&a…

设计模式记--Observer Pattern观察者模式

观察者模式——定义了对象之间的一对多依赖&#xff0c;这样一来&#xff0c;当一个对像改变状态时&#xff0c;它的所有依赖者都会收到通知并自动更新. 从定义可以看出,OBSERVER(观察者)模式逻辑上需要两组对象来实现.首先它必需要有发布者(Publish),也可称为被观察的目标 (…

【C++深度剖析教程9】初探C++标准库

在这之前&#xff0c;我写的C程序不能叫做标准的C程序&#xff0c;因为里面写的大多数还带有C语言的影子。今天我们来学习C标准库。 首先看一下例子&#xff1a;操作符<<的原生意义是按位左移。那么我们重载这个操作符&#xff0c;将变量或者常量&#xff0c;左移到一个…

员工考核UI网页界面(PS大屏文件资料)

现分享人员管理可视化数据统计网页UI、员工考核数据可视化UI网页界面模版的UI源文件&#xff0c;供UI设计师们快速获取PSD源文件完成工作。 若需更多 大屏组件&#xff0c;请移步小7的另一篇文章&#xff1a;数据可视化大屏组件&#xff0c;大屏PSD设计源文件(大屏UI设计规范)…

docker 使用中遇到的问题

1.执行docker run hello 命令建立镜像过程中报错 开始以为是加速器的问题&#xff0c;将/etc/docker/daemon.json 文件删除还是不行 后来执行了这两条命令&#xff1a;就不报错了如下图&#xff1a; systemctl daemon-reloadsystemctl restart docker.service 参考&#xff1…

maven 解决冲突

1.Maven之jar包冲突解决&#xff08;理解maven 产生冲突的原因&#xff09; 导致jar包冲突的原因 1、mvn的传递依赖特性&#xff1a;mvn编译打包除了会引入直接申明的依赖&#xff0c;还会引入间接申明的依赖 2、mvn的依赖仲裁规则&#xff1a; 1&#xff09;. 按照项目总控P…

jz2440开发板修改UBOOT支持NAND FLASH

很多天没有看嵌入式的东西了&#xff0c;今天来看一下&#xff0c;继续之前移植uboot到jz2440开发板。今天我们来实现Uboot支持NAND FLASH。 在之前的文章里&#xff08;点击连接查看之前的记录&#xff09;&#xff0c;我们为了编译通过把NAND FLASH 给屏蔽掉了&#xff0c;现…

i.MX6网卡驱动程序fec.c的分析(AR8035网卡驱动程序的详细分析)之二

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 今天接着分析上次没有分析完的i.MX6网卡驱动程序。上一篇分析了iMX6网卡驱动程序的driver与device的加载过程&#xff08;点击可以查看上一篇文章&…

阅读ethercat官方文档关于ethercat网卡驱动程序的一些内容

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 改造iMX6&#xff08;fec&#xff09;网卡驱动程序前期工作之&#xff1a;阅读ethercat-1.5.2.pdf文档的第四章内容。 ethercat-1.5.2.pdf文档链接&a…

jz2440开发板移植U-boot之修改代码支持DM9000网卡

今天我们来移植U-boot到jz2440开发板&#xff0c;修改代码支持DM9000网卡。查看之前写的移植记录请点击链接&#xff1a;点击查看之前的移植记录 现在大多数开发板都支持DM9000网卡。我们的U-boot源码里面也是有DM9000网卡的驱动程序的。文件为Dm9000x.c&#xff08;drivers\n…

移植U-BOOT之裁剪和修改默认参数(易用性)启动内核,以及对uboot进行分区

今天我们来裁剪U-BOOT&#xff0c;使其更加易用&#xff0c;修改默认参数&#xff0c;以及制作最终修改好得补丁文件方便以后的快速移植。 那么如果想看之前的关于网卡以及flash等的移植&#xff0c;请点击链接查看&#xff1a;点击链接查看 在裁剪修改之前呢&#xff0c;我们…

移植U-BOOT之支持烧写YAFFS文件系统以及制作U-BOOT补丁

今天&#xff0c;我们来移植U-BOOT让其支持YAFFS文件系统映像的烧写&#xff0c;以及最后的终极目标&#xff0c;制作Uboot补丁&#xff0c;因为我们信心苦苦移植好了Uboot&#xff0c;如果换一个地方的或者换一台电脑之类的&#xff0c;我们也不想再浪费时间从头开始移植&…

【数据结构学习之完全从零实现所有数据结构的代码编写之一】泛型编程简介

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 今天开始系统性学习数据结构内容&#xff0c;之前也看过大话数据结构这本书&#xff0c;对大多数概念以及数据结构都有一定的了解&#xff0c;但是就是…

zookeeper 安装和使用

1.Windows安装和使用zookeeper 之前整理过一篇文章《zookeeper 分布式锁服务》&#xff0c;本文介绍的 Zookeeper 是以 3.4.5 这个稳定版本为基础&#xff0c;最新的版本可以通过官网 http://hadoop.apache.org/zookeeper/来获取&#xff0c;Zookeeper 的安装非常简单&#xf…

【移植Linux 3.4.2内核第一步】之简单修改

前一阵子已经将U-boot移植好了&#xff0c;从今天开始&#xff0c;我们开始移植linux内核。移植的内核为3.4.2&#xff0c;移植的开发板为&#xff1a;jz2440开发板。 想看之前移植U-boot的记录&#xff0c;可以查看我的博客专栏&#xff0c;点击链接&#xff1a;点击查看U-bo…

前端学习(77):css中常见margin塌陷问题之解决办法

塌陷问题 当两个盒子在垂直方向上设置margin值时&#xff0c;会出现一个有趣的塌陷现象。 ①垂直并列 首先设置两个DIV,并为其制定宽高 1 1 /*HTML部分*/2 <body>3 <div class"box1">box1</div>4 <div class"box2">box2…

HBase2.0 vs HBase1.x 延时比较

hbase2.0已经正式发布&#xff0c;对比之前1.x版本&#xff0c;2.0在读写链路上做了完善的优化&#xff0c;offheap、netty rpc等&#xff0c;这里做个小测试实验对比1.x和2.0在读写上的延时情况。本测试基于特定测试环境与软件版本得到的结果&#xff0c;仅供参考。 测试介绍 …

【数据结构学习之完全从零实现所有数据结构的代码编写之二】智能指针

今天我们依然暂时不讲解数据结构里面的内容&#xff0c;我们来复习一下昨天学的模板技术用于数据结构编程的思想&#xff0c;给出一个模板技术的实例&#xff1a;智能指针的应用。喜欢看我分享的加我q:1126137994 加我共同学习交流各种技术。 为什么会引入智能指针呢&#xff…