首页 > 编程语言 >C++重载操作符

C++重载操作符

时间:2024-03-28 19:14:36浏览次数:39  
标签:const 函数 对象 C++ 操作符 重载 比较 cmp

在 C++中,重载操作符 < 和重载函数调用操作符 () 各自适用于不同的情况,它们的使用取决于你的具体需求。

比较 < 和 ()

重载操作符 <

  • 排序和比较: 当你需要定义一个类或结构体的对象如何进行排序或比较时,你会重载操作符 <。这在使用标准库中的排序函数(如 std::sort)、集合(如 std::set)或其他需要进行元素比较的算法时特别有用。通过重载 <,你可以指定对象比较的准则,让它们按照特定的顺序排列。

重载函数调用操作符 ()(也称为仿函数或函数对象)

  • 自定义行为的函数调用: 当你希望一个对象的实例能够像函数一样被调用时,你会重载函数调用操作符 ()。这使得对象可以存储状态,同时根据这些状态执行特定的操作。重载 () 的类实例通常被称为仿函数(function objects)或函数对象。
  • 用于算法的自定义操作: 在标准库算法(如 std::sortstd::find_if 等)中,你可以传递函数对象作为参数,用来定义算法的具体行为。这些函数对象可以比普通函数或 lambda 表达式携带更多的信息,因为它们可以有成员变量。
  • 回调函数和策略模式: 仿函数也常用于实现回调函数和策略模式,允许在运行时选择算法的行为。

示例场景

假设你有一个 Student 类,需要根据学生的成绩排序。

  • 重载 < 你会重载 < 来定义两个 Student 对象如何比较,通常是基于它们的成绩。
  • 重载 () 如果你想要在排序时根据不同的标准(如年龄、姓名等)动态选择排序准则,你可以定义一个仿函数,它接受两个 Student 对象,内部根据当前的需求来比较这两个对象。

结论

选择重载 < 还是 () 取决于你的具体需求:如果需要定义对象的默认排序或比较规则,那么重载 < 是合适的。如果你需要更多的灵活性或者想要一个对象表现得像一个可以携带状态的函数,那么重载 () 会是更好的选择。

以 [[重载比较操作符]] 中的代码为例

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
struct Book
{
    int a, b, c;
    bool operator<(const Book &x) const
    {
        if (a != x.a)
            return a < x.a;
        if (b != x.b)
            return b < x.b;
        return c < x.c;
    }
} p[N];

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> p[i].a >> p[i].b >> p[i].c;
    sort(p + 1, p + n + 1);

    for (int i = 1; i <= n; ++i)
        cout << p[i].a << " " << p[i].b << " " << p[i].c << "\n";
    return 0;
}

这段代码可以被修改成

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
struct Book
{
    int a, b, c;
} p[N];
struct cmp{
	bool operator() (const Book &x, const Book &y) const {
		if (x.a != y.a)
            return x.a < y.a;
        if (x.b != y.b)
            return x.b < y.b;
        return x.c < y.c;
	}
};
int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> p[i].a >> p[i].b >> p[i].c;
    sort(p + 1, p + n + 1, cmp());// cmp() 创建匿名对象,调用对象中的方法

    for (int i = 1; i <= n; ++i)
        cout << p[i].a << " " << p[i].b << " " << p[i].c << "\n";
    return 0;
}

上述代码中注释部分的解释

在 C++中,当你向 std::sort(或类似的标准库算法)传递一个比较函数或对象时,传递方式取决于比较逻辑是通过函数还是通过对象实现的。

使用比较函数

如果比较逻辑是以自由函数(或静态成员函数)的形式实现的,你直接传递该函数的名称(不带括号)。这是因为你提供的是函数指针,指向那个实现比较逻辑的函数。

bool compareFunction(const Type& a, const Type& b) {
    // 实现比较逻辑
}

std::sort(arr, arr + n, compareFunction); // 直接传递函数名

使用比较对象

当比较逻辑是通过重载 operator() 的类或结构体(即仿函数或函数对象)实现的,你需要传递该类型的实例。cmp() 在这里是创建 cmp 类型的一个临时对象,这个对象被用作比较的依据。括号是构造函数的调用操作,哪怕该构造函数没有参数,括号也是必须的,以表明你正在构造一个对象。

struct Compare {
    bool operator()(const Type& a, const Type& b) const {
        // 实现比较逻辑
    }
};

std::sort(arr, arr + n, Compare()); // 创建Compare类型的临时对象

因此,当你看到 std::sort(arr, arr + n, cmp()); 这样的调用时,cmp() 表示的是创建一个 cmp 类型的临时对象,而非调用函数。这个对象将会被用作排序算法中的比较基准。如果 cmp 是一个结构体或类,其中重载了 operator(),这样做是完全正确的,且是必需的,因为标准库算法需要一个可以调用的实体来进行元素间的比较。

关于类似 set<int,cmp>的解释

在您提供的代码中,cmp 是用作 multiset 的自定义排序准则。当您这样声明一个 multiset 时:

multiset<int, cmp> st;

您实际上是在告诉 multiset 使用 cmp 作为其元素比较的规则。这里的关键在于 multiset 的模板参数。multiset 是一个模板类,它接受两个参数:元素类型和比较类型。当您指定 cmp 作为第二个模板参数时,您实际上是告诉编译器:“我要使用 cmp 的实例作为比较对象。”

这种情况下,不需要在 cmp 后面加括号,因为您不是在创建一个 cmp 类型的对象实例,而是在指定一个类型。编译器知道如何为 multiset 的内部机制实例化这个比较对象。当 multiset 需要比较其内部元素时,它会自动使用 cmp 类型的一个隐式实例进行比较。

简而言之,在 multiset<int, cmp> st; 这行代码中,cmp 是作为一个类型传递给 multiset 的,所以不需要括号。括号用于创建类型的实例,而在模板参数中,您只是在指定类型本身,实际的实例化过程是自动发生的,无需显式创建实例。

标签:const,函数,对象,C++,操作符,重载,比较,cmp
From: https://www.cnblogs.com/Phantasia/p/18102410

相关文章

  • C/C++ 语言中的 ​if...else if...else 语句
    C/C++语言中的​if...elseif...else语句1.`if`statement2.`if...else`statement3.`if...elseif...else`statementReferences1.ifstatementThesyntaxoftheifstatementis:if(condition){//bodyofifstatement}Thecodeins......
  • 19、C++的指针基础
    1、指针的基本概念(1)变量的地址变量是内存变量的简称,在C++中,每定义一个变量,系统就会给变量分配一块内存,内存是有地址的。C++用运算符&获取变量在内存中的起始地址。语法:&变量名(2)指针变量指针变量简称指针,它是一种特殊的变量,专用于存放变量在内存中的起始地址。语法:数据......
  • C++_基础内容复习-跟着代码学
    二进制文件读写ios_base::out 以写入方式打开文件。ios_base::binary 以二进制模式打开文件std::ofstreamofs(FILE_PATH,ios_base::app);//以追加的形式打开文件//写入学生数量intnumStudents=students.size();ofs.write(reinterpret_cast<constcha......
  • C++第五十七篇——RPC进程间通信
    第一步:新建一个空项目 第二步:新建一个IDL 第三步:生成一个GUID,编写RPCConn.idl RPCConn.idlimport"oaidl.idl";import"ocidl.idl";[uuid(1BA624D4-DC7D-484C-AF8C-0EF86C4A0555),version(1.0)]interfaceRPCConn{intAdd([in]inta,......
  • C++入门————第一天
    1、命名空间     在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。  1......
  • SAP Fiori开发中的JavaScript基础知识2 - 变量,操作符,值,类型
    1.JavaScript代码示例在介绍JavaScript具体语法前,让我们先看一段在Web应用程序过程中的JS代码片。<!DOCTYPEhtml><html> <head> <metacharset="utf-8"/> <title>FirstJavaScriptApplication!</title> <scriptsrc="js/myExternal.js&q......
  • Linux C++ 007-指针
    LinuxC++007-指针本节关键字:Linux、C++、指针、函数指针相关库函数:基本概念指针的作用:可以通过指针间接访问内存。内存编号是从0开始记录的,一般用于十六进制数字表示,可以利用指针变量保存地址。定义和使用指针变量定义语法:数据类型*变量名;指针所占内存空间,指针......
  • Linux C++ 008-结构体
    LinuxC++008-结构体本节关键字:Linux、C++、结构体相关库函数:基本概念结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。定义和使用语法:struct结构体名{结构体成员列表};通过结构体创建变量的方式有三种struct结构体名变量名struct结构体名变......
  • C++ Primer Plus 代码学习解析(第三章 3.8-3.11)
    3.8floatnum.cpp#include<iostream>intmain(){usingnamespacestd;cout.setf(ios_base::fixed,ios_base::floatfield);floattub=10.0/3.0;doublemint=10.0/3.0;constfloatmillion=1.0e6;cout<<&......
  • C++之STL整理(2)之vector超详用法整理
    C++之STL整理(2)之vector用法(创建、赋值、方法)整理注:整理一些突然学到的C++知识,随时mark一下例如:忘记的关键字用法,新关键字,新数据结构C++的vector用法整理C++之STL整理(2)之vector用法(创建、赋值、方法)整理一、vector的初始化1、默认构造函数2、拷贝构造函数copy区间3......