重学C++系列之友元

news/2024/12/22 2:05:07/

一、什么是友元

        在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; // 先声明一个类Testclass 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;
}

五、总结

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


http://www.ppmy.cn/news/987706.html

相关文章

react的特点

React的特点包括以下几个方面&#xff1a; 组件化&#xff1a;React将用户界面分解成小而独立的组件&#xff0c;每个组件都有自己的状态和属性。通过组合这些组件&#xff0c;可以构建复杂而灵活的用户界面。 虚拟DOM&#xff1a;React使用虚拟DOM&#xff08;Virtual DOM&am…

Docker容器监控之 CAdvisor+InfluxDB+Granfana

通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据&#xff0c;一般小公司够用了。但是&#xff0c;docker stats统计结果只能是当前宿主机的全部容器&#xff0c;数据资料是实时的&#xff0c;没有地方存储、没有健康指标过线预警等功能…

Redis三种模式——主从复制,哨兵模式,集群

目录 一、主从复制 1.1主从复制的概念 1.2Redis主从复制作用 1.2.1数据冗余 1.2.2故障恢复 1.2.3负载均衡 1.2.4高可用基石 1.3Redis主从复制流程 1.4部署Redis 主从复制 1.4.1.环境部署 1.4.2.所有服务器都先关闭防火墙 1.4.3.所有服务器都安装Redis 1.4.4修改Master主节点R…

好大一个坑:在Nginx上将PHP网页放在二级目录

1、原由 只有一个域名&#xff0c;以前用php编写的网页又不能放弃&#xff0c;考虑将其移至二级目录下&#xff0c;例如&#xff1a; https://abc.com/html2、运行环境 Linux服务器上&#xff0c;用docker容器。Nginx和php-fpm各自运行在不同的容器中&#xff0c;Nginx在前端…

Numpy-聚合函数

NumPy 提供了很多统计函数&#xff0c;用于从数组中查找最小元素&#xff0c;最大元素&#xff0c;百分位标准差和方差等。 函数名说明np.sum()求和np.prod()所有元素相乘np.mean()平均值np.std()标准差np.var()方差np.median()中位数np.power()幂运算np.sqrt()开方np.min()最小…

MySQL中锁的简介——表级锁-元数据锁、意向锁

1.元数据锁 查看元数据锁 select object_type,object_scheme,object_name,lock_type,lock_duration from perfomance_scheme.metadata_locks;2.意向锁 线程A开启事务后在执行update更新语句时候&#xff0c;会给数据加上行锁&#xff0c;加上行锁以后&#xff0c;会对整张表加…

Redis实战(3)——缓存模型与缓存更新策略

1 什么是缓存? 缓存就是数据交换的缓冲区&#xff0c; 是存贮数据的临时区&#xff0c;一般读写性能较高 \textcolor{red}{是存贮数据的临时区&#xff0c;一般读写性能较高} 是存贮数据的临时区&#xff0c;一般读写性能较高。缓存可在多个场景下使用 以一次 w e b 请求为例…

flink源码分析-获取JVM最大堆内存

flink版本: flink-1.11.2 代码位置: org.apache.flink.runtime.util.EnvironmentInformation#getMaxJvmHeapMemory 如果设置了-Xmx参数&#xff0c;就返回这个参数&#xff0c;如果没设置就返回机器物理内存的1/4. 这里主要看各个机器内存的获取方法。 /*** The maximum JVM…