【友元】

在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术

友元的目的就是让一个函数或者类 访问另一个类中私有成员

友元的关键字为 friend

友元的三种实现

  • 全局函数做友元
  • 类做友元
  • 成员函数做友元

全局函数友元

新建一个Building类,里面有客厅(public)和卧室(private)两个属性

class Building {

//行为
public:
//构造函数
Building() {
m_SittingRoom = "客厅";
m_BadRoom = "卧室";
} //属性
public:
string m_SittingRoom;
private:
string m_BadRoom;
}; int main() {
system("pause");
return 0;
}

在main外部(全局)创建一个函数goodGay,分别访问两个属性。

使用test01函数测试,当然私有属性要访问时会报错

class Building {

//行为
public:
//
Building() {
m_SittingRoom = "客厅";
m_BadRoom = "卧室";
} //属性
public:
string m_SittingRoom;
private:
string m_BadRoom;
}; void goodGay(Building *building) {
cout << "好基友正在访问: " << building->m_SittingRoom << endl;
//cout << "好基友正在访问: " << building->m_BedRoom << endl;
} void test01() {
Building building;
goodGay(&building);
} int main() { test01(); system("pause");
return 0;
}

这时,需要将void goodGay(Building *building)添加到Building类的开头,并以关键字‘friend’修饰

#include<iostream>
using namespace std;
#include<string> class Building { //声明友元
friend void goodGay(Building* building); //行为
public:
//
Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
} //属性
public:
string m_SittingRoom;
private:
string m_BedRoom;
}; void goodGay(Building *building) {
cout << "好基友正在访问: " << building->m_SittingRoom << endl;
cout << "好基友正在访问: " << building->m_BedRoom << endl;
} void test01() {
Building building;
goodGay(&building);
} int main() {
test01(); system("pause");
return 0;
}

由此,友元全局函数goodGay便可以访问Building类中的私有属性

类友元

例子的框架与之前类似

只是这次我们需要创建一个GoodGay类去访问

补充知识点:类外写成员函数

例如,现在有一个Building类

class Building
{
public:
Building();
public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
}; int main(){ system("pause");
return 0;
}

该类中的构造函数(也是成员函数之一)只是声明还没有实现,我们可以在类外对其进行实现

class Building
{
public:
Building();
public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
}; //类外实现成员函数
//"xxx :: xx函数",xxx表示声明了函数的作用域
Building::Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
} int main(){ system("pause");
return 0;
}

例子

根据上面的方法,我们在GoodGay类和Building类外面分别实现其构造函数

#include<iostream>
using namespace std;
#include<string> class Building;
class goodGay
{
public: goodGay();
void visit(); private:
Building *building;
}; class Building
{
//告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
friend class goodGay; public:
Building(); public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
}; //类外实现构造函数Building()
//作用域在Building类下
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
} //类外实现goodGay构造函数
//作用域在goodGay类下
goodGay::goodGay()
{
//在堆区创建建筑物对象
//goodGay类中的Building *building指向该对象
building = new Building;
} //类外实现goodGay的成员函数
//作用域在goodGay类下
void goodGay::visit()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
cout << "好基友正在访问" << building->m_BedRoom << endl;
} void test01()
{
goodGay gg;
gg.visit(); } int main(){ test01(); system("pause");
return 0;
}

GoodGay类能访问Building类的私有属性的关键也是使用友元

即在Building类开头用‘friend’修饰

class Building
{
//告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
friend class goodGay; public:
...

成员函数友元

例子

#include<iostream>
using namespace std;
#include<string> class Building;
class goodGay
{
public:
goodGay();
void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
void visit2(); private:
Building *building;
}; class Building
{
//告诉编译器 goodGay类中的visit成员函数 是Building好朋友,可以访问私有内容
friend void goodGay::visit(); public:
Building(); public:
string m_SittingRoom; //客厅
private:
string m_BedRoom;//卧室
}; //类外实现构造函数Building()
//作用域在Building类下
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
} //类外实现构造函数goodGay()
//作用域在goodGay类下
goodGay::goodGay()
{
building = new Building;
} //类外实现成员函数visit()
//作用域在goodGay类下
void goodGay::visit()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
cout << "好基友正在访问" << building->m_BedRoom << endl;
} //类外实现成员函数visit2()
//作用域在goodGay类下
void goodGay::visit2()
{
cout << "好基友正在访问" << building->m_SittingRoom << endl;
//cout << "好基友正在访问" << building->m_BedRoom << endl;
} void test01()
{
goodGay gg;
gg.visit();
} int main(){
test01(); system("pause");
return 0;
}

技巧

如果之后要用到某个类,但是该类的细节还没有写,可以先写个占位的代码

class Building;
class goodGay{
public:
goodGay();
void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
void visit2(); private:
//用到了但还没写
Building *building;
}; ...
//之后再定义
class Building{ }

【C++ OOP 03 友元】各种友元例子以及如何类外写成员函数的更多相关文章

  1. c++友元函数、友元类、友成员函数

    友元函数:不是类成员函数,是一个类外的函数,但是可以访问类所有成员. class Point{ public: friend void fun(Point t);//友元函数 private: int ...

  2. C++ 友元(friend关键字)、类中的重载、操作符重载(operator关键字)

    C++ 中友元的用法: 1.在类中使用friend关键字声明 2.类的友元可以是其它类或者具体函数 3.友元不是类的一部分 4.友元不受类中访问级别的限制 5.友元可以直接访问具体类中的所有成员. 友 ...

  3. 友元(友元函数、友元类和友元成员函数) C++

    有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的.例如被重载的操作符,如输入或输出操作符,经常需要访问类的私有数据成员. 友元(frend)机制允许一个类将 ...

  4. C++友元(友元函数、友元类和友元成员函数)

    友元(友元函数.友元类和友元成员函数) C++ 有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的.例如被重载的操作符,如输入或输出操作符,经常需要访问类的私 ...

  5. C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 对运算符重载的函数有两种处理方式:(1)把运算符 ...

  6. C++ 友元 (全局函数做友元) (类做友元) (成员函数做友元)

    1 //友元 全局函数做友元 2 /* 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 7 ...

  7. C++基础-4-封装(构造函数与析构函数,深拷贝与浅拷贝,静态成员,this,友元,const修饰成员函数)

    4. 封装 4.1.1 封装的意义 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 con ...

  8. 读书笔记 effective c++ Item 23 宁可使用非成员非友元函数函数也不使用成员函数

    1. 非成员非友元好还是成员函数好? 想象一个表示web浏览器的类.这样一个类提供了清除下载缓存,清除URL访问历史,从系统中移除所有cookies等接口: class WebBrowser { pu ...

  9. C++运算符重载三种形式(成员函数,友元函数,普通函数)详解

    首先,介绍三种重载方式: //作为成员函数重载(常见) class Person{ Private: string name; int age; public: Person(const char* ...

  10. 重载运算符:类成员函数or友元函数

    类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...

随机推荐

  1. [转帖]使用 Shell 运算进行进制转换 16进制转10进制

    使用 Shell 运算进行进制转换 工作时候常常遇到一些问题,拿到的数字是16进制的,但是运算的时候是10进制的,shell可以很方便的处理这类的进制转换问题,一种情况是使用 Shell 运算把一个数 ...

  2. 袋鼠云数栈产品中 AI+ 实现原理剖析

    生产力工具 + AI 是不可逆转的趋势,慢慢的大模型能力通过 AI Agent 落地的工程化能力也开始趋于成熟.作为大数据产品的数栈也必然是需要借助 AI 能力提升产品竞争力. 去年 12 月,我们在 ...

  3. TypeScript中的元组 Tuple

    元组类型 // 元组类型:表示一个已知元素数量和类型的数组,各元素的类型不必相同 let undata: [string, '男'| '女']; //已知数量是两个.类型分别是字符串和男或者女 und ...

  4. 【K哥爬虫普法】你很会写爬虫吗?10秒抢票、10秒入狱,了解一下?

    我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K 哥特设了"K哥爬虫普法"专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识, ...

  5. 手把手教学小型金融知识图谱构建:量化分析、图数据库neo4j、图算法、关系预测、命名实体识别、Cypher Cheetsheet详细教学等

    手把手教学小型金融知识图谱构建:量化分析.图数据库neo4j.图算法.关系预测.命名实体识别.Cypher Cheetsheet详细教学等 效果预览: 1. 知识图谱存储方式 知识图谱存储方式主要包含 ...

  6. 5.11 汇编语言:仿写IF条件语句

    条件语句,也称为IF-ELSE语句,是计算机编程中的一种基本控制结构.它允许程序根据条件的真假来执行不同的代码块.条件语句在处理决策和分支逻辑时非常有用.一般来说,条件语句由IF关键字.一个条件表达式 ...

  7. Linux 统计Web服务日志命令

    本人在Linux运维中收集的一些通用的统计,Apache/Nginx服务器日志的命令组合. Apache日志统计 # 列出当天访问次数最多的IP命令 [root@lyshark.cnblogs.com ...

  8. C/C++ 关于运算符重载笔记

    加号运算符重载: 重载加号运算符,让 p3 = p1 + p2 改成 p3.mage = p1.mage + p2.mage 实现两个数据成员的相加. 告诉编译器,两个类中的数据成员应该怎么相加. 成 ...

  9. Linux 配置Quota磁盘配额

    由于Linux是一个多用户管理的操作系统,而Linux默认情况下并不限制每个用户使用磁盘空间的大小,假如某个用户疏忽或者恶意占满磁盘空间,将导致系统磁盘无法写入甚至崩溃,为了保证系统磁盘的有足够的剩余 ...

  10. ROS节点通信(二)service和client

    目录 1.说明 2.创建功能包 3.自定义通信数据类型 4.编写代码 5.编译配置 5.1.CMakeLists.txt 5.2.package.xml 6.编译运行 1.说明 ROS的节点通信模式有 ...