C++基础:Stanford CS106L学习笔记 12 运算符重载

目录

      • [12.1 运算符重载](#12.1 运算符重载)
      • [12.2 非成员重载](#12.2 非成员重载)
      • [12.3 友元(Freind)](#12.3 友元(Freind))
      • [12.4 实践方法](#12.4 实践方法)

运算符能让你传达一些关于类型的含义,而这是函数做不到的。

运算符是如何与类一起工作的呢?

  • 就像我们在类中声明函数一样,我们也可以声明运算符的功能。
  • 当我们将该运算符用于我们的新对象时,它会执行一个自定义的函数或操作。
  • 就像在函数重载中一样,如果我们给它取相同的名称,它会覆盖运算符的行为!

12.1 运算符重载

运算符重载是 C++ 允许用 "自定义方式" 重定义+<==等运算符的机制,让自定义类(如这里的StanfordID,推测是 "斯坦福 ID" 类)能像内置类型(如int)一样用运算符比较 / 计算。

哪些运算符不能被重载?

  • 作用域解析
  • 三元运算
  • 成员访问
  • 指向成员的指针访问
  • 对象大小、类型和强制转换

.h文件

cpp 复制代码
class StanfordID {
private:
    std::string name;
    std::string sunet;
    int idNumber;
public:
    // constructor for our StanfordID
    StanfordID(std::string name, std::string sunet, int idNumber);
    ... 
    bool operator < (const StanfordID& rhs) const;
}

.cpp文件

cpp 复制代码
#include StanfordID.h
std::string StanfordID::getIdNumber() {
    return idNumber;
}
bool StanfordID::operator<(const StanfirdID& other) const {
    return idNumber < other.getIdNumber();
}

12.2 非成员重载

重载有两种方式:

  1. 成员重载

    a. 在类的作用域内声明重载运算符

  2. 非成员重载

    a. 在类定义外部声明重载运算符

    b. 将左侧和右侧对象都定义为参数

非成员重载:

这实际上是 STL 所偏好的,并且更符合(C++ 的)习惯用法。

原因如下:

  1. 允许左侧为非类类型
  2. 允许我们对不属于自己的类重载运算符 我们可以定义一个运算符来比较 StanfordID 与你定义的其他自定义类。

12.3 友元(Freind)

非成员函数的缺点是:默认无法访问类的​私有(private)成员​(C++ 类的封装性规定,只有类内成员 / 友元能访问私有成员)。

friend关键字的核心作用就是 "打破封装限制":

  • 如果在StanfordID类的内部,用friend bool operator<(const StanfordID&, const StanfordID&);声明这个非成员的<重载函数为 "友元";
  • 那么这个operator<函数就能直接访问StanfordID的私有成员(比如StanfordID可能用私有变量idNum存储 ID 号,重载函数需要比较lhs.idNumrhs.idNum,没有friend就会编译报错)。

.h文件

cpp 复制代码
class StanfordID {
private:
    std::string name;
    std::string sunet;
    int idNumber;
public:
// constructor for our StudentID
StanfordID(std::string name, std::string sunet, int idNumber);
    .
    .
    . 
    // 声明友元函数
    friend bool operator < (const StanfordID& lhs, const StanfordID& rhs);
}

以下代码可以正常运行:

.cpp文件

cpp 复制代码
#include StanfordID.h
bool operator< (const StanfordID& lhs, const StanfordID& rhs)
{
    return lhs.idNumber < rhs.idNumber;
}

以下代码也可以正常运行,在这种情况下,不需要使用 "friend" 关键字,因为我们没有使用私有成员函数或变量。

cpp 复制代码
#include StanfordID.h
bool operator< (const StanfordID& lhs, const StanfordID& rhs)
{
    return lhs.getIdNumber() < rhs.getIdNumber();
}

12.4 实践方法

由于运算符旨在传达有关某种类型的含义,这种含义应当是显而易见的。

我们可以定义的运算符通常是算术运算符。其功能应当与其相应的运算在合理范围内保持相似。你不会希望将 operator + 定义为集合减法。如果含义不明确,那么或许可以为此定义一个函数。

这被称为​最小惊讶原则(PoLA​)。

有一些良好的实践方法,比如​相反规则​。例如,当你定义 "==" 运算符时,使用相反规则来定义 "!=" 运算符。

cpp 复制代码
bool StanfordID::operator==(const StanfordID& other) const {
    return (name == other.name) && (sunet == other.sunet) &&
    (idNumber == other.idNumber);
}
bool StanfordID::operator!=(const StanfordID& other) const {
    return !(*this == other);
}
相关推荐
W23035765732 小时前
经典算法:最长上升子序列(LIS)深度解析 C++ 实现
开发语言·c++·算法
.Ashy.2 小时前
2026.4.11 蓝桥杯软件类C/C++ G组山东省赛 小记
c语言·c++·蓝桥杯
minji...3 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
CoderCodingNo5 小时前
【GESP】C++三级真题 luogu-B4499, [GESP202603 三级] 二进制回文串
数据结构·c++·算法
炽烈小老头5 小时前
【 每天学习一点算法 2026/04/12】x 的平方根
学习·算法
阿杰学AI6 小时前
AI核心知识115—大语言模型之 自监督学习(简洁且通俗易懂版)
人工智能·学习·ai·语言模型·aigc·监督学习·自监督学习
hetao17338376 小时前
2026-04-09~12 hetao1733837 的刷题记录
c++·算法
九英里路6 小时前
OS学习之路——动静态库制作与原理
linux·学习·操作系统·unix·进程·编译·动静态库
6Hzlia6 小时前
【Hot 100 刷题计划】 LeetCode 136. 只出现一次的数字 | C++ 哈希表&异或基础解法
c++·算法·leetcode
汉克老师7 小时前
GESP2024年6月认证C++三级( 第二部分判断题(1-10))
c++·数组·位运算·补码·gesp三级·gesp3级