C++:友元

内容提要

  • 面向对象

    • 友元

友元

生活中的你家有客厅(public),有卧室(private)

客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你自己可以进入。

但是呢,你也可以允许客人中你的朋友进去。

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

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

友元的关键字为friend

友元的三种实现:

①全局函数做友元

②类做友元

③成员函数做友元

全局函数做友元

复制代码
 /*************************************************************************
   > File Name:    demo01.cpp
   > Author:       柯柯大王
   > Description:  友元:全局函数做友元
   > Created Time: 2025-08-21 08:52:42
  ************************************************************************/
 #include <iostream>
 #include <string>
 #include <iomanip>
 ​
 using namespace std;
 ​
 //创建Building类
 class Building
 {
     //告诉编译器 goodFriend全局函数 是Building类的好朋友,可以访问类中的私有成员
     friend void goodFriend(Building* building); //friend 函数
 public:
     //无参构造,此时会覆盖掉默认的无参
     Building()
     {
         //赋值
         this->sittingRoom = "客厅";
         this->bedRoom = "卧室";
     }
 public:
     string sittingRoom;    //客厅  公共成员
 private:
     string bedRoom;        //卧室  私有成员
 };
 ​
 //准备一个全局函数,用来做友元,实现对类中私有成员 bedRoom的访问
 void goodFriend(Building* building)
 {
     cout << "好朋友正在造访:" << building->sittingRoom << endl;   //客厅,正常访问
     cout << "好朋友正在造访:" << building->bedRoom << endl;       //卧室,需要借助友元访问
 }
 ​
 int main(int argc, char **argv)
 {
     Building b;
     goodFriend(&b);
     
     system("pause");
     return 0;
 }

类做友元

复制代码
 /*************************************************************************
   > File Name:    demo02.cpp
   > Author:       柯柯大王
   > Description:  友元:类做友元
   > Created Time: 2025-08-21 09:58:18
  ************************************************************************/
 #include <iostream>
 #include <string>
 #include <iomanip>
 ​
 using namespace std;
 ​
 //创建类BUilding
 class Building
 {
     //告诉编译器 GoodFriend类是Building类的好朋友,可以访问到Building类中的私有成员
     friend class GoodFriend;
 public:
     Building();
     string sittingRoom;   //客厅  公共成员
 private:
     string bedRoom;        //卧室  私有成员
 };
 ​
 //定义Building类的构造函数
 Building::Building()
 {
     this->sittingRoom = "客厅";
     this->bedRoom = "卧室";
 }
 ​
 //创建类GoodFriend
 class GoodFriend
 {
 public:
     GoodFriend()
     {
         this->building = new Building(); //此时就不在栈区,在 自由存储区,大概率在堆区
     }
     
     //访问好朋友(友元)Building的私有成员
     void visit()
     {
         cout << "好朋友正在造访:" << building->sittingRoom << endl;   //客厅,正常访问
         cout << "好朋友正在造访:" << building->bedRoom << endl;       //卧室
     }
 private:
     Building *building; 
 };
 ​
 //void GoodFriend::visit()
 //{
 //  cout << "好朋友正在造访:" << building->sittingRoom << endl;   //客厅,正常访问
 //  cout << "好朋友正在造访:" << building->bedRoom << endl;       //卧室 
 //}
 ​
 int main(int argc, char **argv)
 {
     GoodFriend gf;
     gf.visit();
     
     system("pause");
     return 0;
 }

成员函数做友元

复制代码
 #include <iostream>
 #include <string>
 #include <iomanip>
 using namespace std;
 // 类的声明,主要是解决类的嵌套
 class Building;
 // 类的定义
 // 创建友元类
 class GoodFriend
 {
 public:
  GoodFriend();
  
  void visit();
 private:
  Building *building; 
 };
 // 创建Building类
 class Building
 {
  // 告诉编译器 GoodFrind类中某个函数(visit)作为Building类的好朋友,可以
 访问Building中的私有成员
  friend void GoodFriend::visit();
 public:
  // 无参构造函数
  Building()
  {
  // 初始化(所谓初始化,就是给类对象的成员变量赋初值)
  this->sittingRoom = "客厅";
  this->bedRoom = "卧室";
  }
 public:
  string sittingRoom;    // 客厅 公共成员
 private:
  string bedRoom;        // 卧室 私有成员
  
 };
 GoodFriend::GoodFriend()
 {
  this->building = new Building();
 }
 void GoodFriend::visit()
 {
  cout << "好朋友正在造访:" << building->sittingRoom << endl;  // 客
 厅,正常访问
  cout << "好朋友正在造访:" << building->bedRoom << endl;      // 卧
 室,需要借助友元访问
 }
 int main(int argc, char **argv)
 {
  GoodFriend gf;
  gf.visit();
  
  system("pause");
  return 0;
 }    

如果涉及到类的嵌套访问,比如成员函数做友元的时候。我们建议将成员函数定义到类的外部,同时需要给类加上类声明。

运算符重载【了解】

运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以使用不同的数据类型。

加号运算符

**作用:**实现两个自定义数据类型相加的运算

示例:

复制代码
 #include <iostream>
 #include <string>
 #include <iomanip>
 using namespace std;
 class Person
 {
 public:
  Person(){}
  Person(int a, int b)
  {
  this->a = a;
  this->b = b;
  }
  
  // 成员函数实现 + 号运算符重载
 Person operator+(const Person& p)
  {
  Person temp;
  temp.a = this->a + p.a;
  temp.b = this->b + p.b;
  return temp;
  }
 public:
  int a;
  int b;
 };
 // 全局函数实现 + 号运算符重载
 Person operator+(const Person& p1, const Person& p2)
 {
  Person temp;
  temp.a =p1.a + p2.a;
  temp.b =p1.b + p2.b;
  return temp;
 }
 // 运算符重载 可以发生函数重载
 Person operator+(const Person& p2, int val)
 {
  Person temp;
  temp.a =p2.a + val;
  temp.b =p2.b + val;
  return temp;
 }
 int main(int argc, char **argv)
 {
  Person p1(10,20);
  Person p2(20,20);
  
  // 测试成员函数方式
  Person p3 = p2 + p1;  // 相当于 p3 = p2.operator+(p1)
  cout << "a = " << p3.a << ",b = " << p3.b  << endl;
  
  Person p4 = p3 + 10;  // 相当于 p4 = operator+(p3, 10)
  cout << "a = " << p4.a << ",b = " << p4.b  << endl;
  system("pause");
  return 0;
 }
 ​

总结1:对于内置的数据类型的表达式的运算符是不可能改变的
总结2:不要滥用运算符重载

相关推荐
资深web全栈开发17 小时前
[特殊字符]图解 Golang 反射机制:从底层原理看动态类型的秘密
开发语言·后端·golang
报错小能手1 天前
C++笔记——STL map
c++·笔记
独隅1 天前
在 Lua 中,你可以使用 `os.date()` 函数轻松地将时间戳转换为格式化的时间字符串
开发语言·lua
思麟呀1 天前
Linux的基础IO流
linux·运维·服务器·开发语言·c++
星释1 天前
Rust 练习册 :Pythagorean Triplet与数学算法
开发语言·算法·rust
星释1 天前
Rust 练习册 :Nth Prime与素数算法
开发语言·算法·rust
lkbhua莱克瓦241 天前
Java基础——集合进阶3
java·开发语言·笔记
多喝开水少熬夜1 天前
Trie树相关算法题java实现
java·开发语言·算法
QT 小鲜肉1 天前
【QT/C++】Qt定时器QTimer类的实现方法详解(超详细)
开发语言·数据库·c++·笔记·qt·学习
WBluuue1 天前
数据结构与算法:树上倍增与LCA
数据结构·c++·算法