草庐IT

十个 C++ 运算符重载示例,看完不懂打我...

阿基米东 2023-11-03 原文

下面是一些 C++ 运算符重载示例,包括算术运算符、赋值运算符、逻辑运算符、成员运算符、关系运算符等等,这些都是使用频率较高的几个运算符重载案例。

⭐️ 所有示例代码均存放于 GitHub: getiot/cpp-courses/operator_overloading


示例 1:一元运算符重载

一元运算符即只对一个操作数进行操作的运算符,例如:!obj-obj++objobj++obj-- 等等。

下面示例将对负号(-)进行重载:

#include <iostream>
using namespace std;

class Distance
{
private:
    int feet;    // 0 到无穷
    int inches;  // 0 到 12
public:
    // 构造函数
    Distance() {
        feet = 0;
        inches = 0;
    }
    Distance(int f, int i) {
        feet = f;
        inches = i;
    }
    
    // 显示距离
    void displayDistance() {
        cout << "F: " << feet << ", I: " << inches << endl;
    }
    
    // 重载负运算符 ( - )
    Distance operator- () {
        feet = -feet;
        inches = -inches;
        return Distance(feet, inches);
    }
};

int main(void)
{
    Distance d1(1, 10), d2(-5, 110);
    
    -d1;                     // 取相反数
    d1.displayDistance();    // 距离 D1
    
    -d2;                     // 取相反数
    d2.displayDistance();    // 距离 D2
    
    return 0;
}

编译并运行以上示例,输出结果如下:

F: -1, I: -10
F: 5, I: -110

示例 2:二元运算符重载

二元运算符即需要两个参数的运算符,例如:加运算符(+)、减运算符(-)、乘运算符(*)、除运算符(/)。

下面示例将重载加运算符(+):

#include <iostream>
using namespace std;

class Box
{
    double length;  // 长度
    double width;   // 宽度
    double height;  // 高度

public:
    Box () {
        length = 0.0;
        width  = 0.0;
        height = 0.0;
    }

    Box (double a, double b ,double c)
    {
        length = a;
        width  = b;
        height = c;        
    }

    double getVolume(void)
    {
        return length * width * height;
    }

    // 重载 + 运算符,用于把两个 Box 对象相加
    Box operator+(const Box& b)
    {
        Box box;
        box.length = this->length + b.length;
        box.width  = this->width + b.width;
        box.height = this->height + b.height;
        return box;
    }
};

int main(void)
{
    Box b1(5.0, 4.0, 3.0);
    Box b2(6.0, 5.0, 4.0);
    Box b3;

    cout << "Volume of b1 : " << b1.getVolume() << endl;
    cout << "Volume of b2 : " << b2.getVolume() << endl;

    // 把两个对象相加,得到 Box3
    b3 = b1 + b2;

    // Box3 的体积
    cout << "Volume of b3 : " << b3.getVolume() << endl;

    return 0;
}

使用 g++ main.cpp && ./a.out 命令编译运行以上示例,输出结果如下:

Volume of b1 : 60
Volume of b2 : 120
Volume of b3 : 693

示例 3:关系运算符重载

C++ 允许重载任何一个关系运算符(例如 < 、 > 、 <= 、 >= 、 == 等),重载后的关系运算符可用于比较类的对象。许多 C++ 内置的数据类型也都支持各种关系运算符。

下面示例将重载小于符(<):

#include <iostream>
using namespace std;

class Rect
{
private:
    double width;
    double height;

public:
    Rect(double a, double b)
    {
        width  = a;
        height = b;
    }

    double area() {
        return width * height;
    }

    // 重载小于运算符 ( < ), 按照面积比大小
    bool operator<(Rect& that)
    {
        return this->area() < that.area();
    }
};

int main()
{
    Rect r1(3.0, 5.0), r2(3.5, 4.5);

    cout << "Area of r1 = " << r1.area() << endl;
    cout << "Area of r2 = " << r2.area() << endl;

    if ( r1 < r2 )
        cout << "r1 is less than r2" << endl;
    else
        cout << "r1 is large than r2" << endl;

   return 0;
}

编译运行以上代码,输出结果如下:

Area of r1 = 15
Area of r2 = 15.75
r1 is less than r2

示例 4:输入/输出运算符重载

C++ 使用流提取运算符>>)和流插入运算符<<)来输入和输出内置的数据类型,同时也允许重载 >><< 来操作对象等用户自定义的数据类型。

可以把运算符重载函数声明为类的友元函数,这样就可以不用创建对象而直接调用函数。

#include <iostream>
using namespace std;

class Rect
{
public:
    double width;
    double height;

    Rect() {
        width = 0;
        height = 0;
    }

    Rect(double a, double b )
    {
        width  = a;
        height = b;
    }

    double area() {
        return width * height;
    }

    friend std::ostream &operator<<(std::ostream &output, Rect &r)
    { 
        output << "width: " << r.width << ", ";
        output << "height: " << r.height << ", ";
        output << "area: " << r.area();

        return output;
    }

    friend std::istream &operator>>(std::istream &input, Rect &r)
    {
        input >> r.width >> r.height;
        return input;            
    }
};

int main()
{
    Rect r1(3.0, 4.0), r2(6.0, 8.0), r3;
    
    cout << "Enter the value of object: \n";
    cin >> r3;
    cout << "r1: " << r1 << endl;
    cout << "r2: " << r2 << endl;
    cout << "r3: " << r3 << endl;
    
    return 0;
}

编译和运行以上示例,输出结果如下:

Enter the value of object: 
2 3
r1: width: 3, height: 4, area: 12
r2: width: 6, height: 8, area: 48
r3: width: 2, height: 3, area: 6

示例 5:++ 和 – 运算符重载

递增运算符(++)和递减运算符(--)是 C++ 语言中两个重要的一元运算符,包括前缀和后缀两种用法。

下面示例将演示如何重载前缀自增(++obj)和后缀自减运算符(obj--):

#include <iostream>
using namespace std;

class Time
{
private:
    int minute;             
    int second;

public:
    Time () {
        minute = 0;
        second = 0;
    }

    Time (int m, int s) {
        minute = m;
        second = s;
    }

    void display() {
        cout << minute << " : " << second << endl;
    }

    // 重载前缀递增运算符 ( ++ )
    Time operator++() {
        second++;

        if (second >= 60) {
            minute++;
            second = 0;
        }

        return Time(minute, second);
      }
    
    // 重载后缀递增运算符( ++ )
    Time operator++(int)
    {
        Time t(minute, second);  // 保存原始值
        second++;                // 对象加 1

        if (second >= 60) {
            minute++;
            second = 0;
        }

        return t;  // 返回旧的原始值
    }
};

int main()
{
    Time t1(12, 58), t2(0,45);
    
    t1.display();
    (++t1).display();
    (++t1).display();
    
    t2.display();
    (t2++).display();
    (t2++).display();
    
    return 0;
}

编译运行以上示例,输出结果如下:

12 : 58
12 : 59
13 : 0
0 : 45
0 : 45
0 : 46

示例 6:赋值运算符重载

C++ 允许重载赋值运算符(=),用于创建一个对象,比如拷贝构造函数。

下面示例重载 Rect 中的赋值运算符,并在每次拷贝的时候就把长度和宽度数值各加 1。

#include <iostream>
using namespace std;

class Rect
{
private:
    double width;
    double height;

public:
    Rect() {
        width = 0;
        height = 0;
    }

    Rect(double a, double b) {
        width = a;
        height = b;
    }

    void display() {
        cout << " width: " << width;
        cout << " height: " << height;
    }

    void operator= (const Rect &r)
    {
        width = r.width + 1;
        height = r.height + 1;
    }
};

int main()
{
    Rect r1(3.0, 4.0), r2;
    
    r2 = r1;

    cout << "r1: ";
    r1.display();
    cout << endl;

    cout << "r2: ";
    r2.display();
    cout << endl;

    return 0;
}

编译和运行以上示例,输出结果如下:

r1:  width: 3 height: 4
r2:  width: 4 height: 5

示例 7:函数调用运算符重载

C++ 允许重载函数调用运算符(即 () 符号)。重载 () 的目的不是为了创造一种新的调用函数的方式,而是创建一个可以传递任意个参数的运算符函数。其实就是创建一个可调用的对象。

下面示例将演示重载函数调用运算符的妙用:

#include <iostream>
using namespace std;

class Rect
{
private:
    int width;
    int height;

public:
    Rect() {
        width  = 0;
        height = 0;
    }

    Rect(int a ,int b) {
        width  = a;
        height = b;
    }

    void operator()() {
        cout << "Area of myself is:" << width * height << endl;
    }
};

int main()
{
    Rect r1(3, 4), r2(6, 8);

    cout << "r1: "; 
    r1();

    cout << "r2: ";
    r2();
    
    return 0;
}

编译和运行以上示例,输出结果如下:

r1: Area of myself is:12
r2: Area of myself is:48

示例 8:下标运算符重载

下标操作符([])通常用于访问数组元素。C++ 允许重载下标运算符用于增强操作 C++ 数组的功能,重载下标运算符最重要的作用就是设置一个哨兵,防止数组访问越界。

下面示例演示重载下标运算符:

#include <iostream>
using namespace std;

const int SIZE = 10;

class Fibo
{
private:
    // 偷懒,防止把 SIZE 设置的过小
    int arr[SIZE+3];

public:
    Fibo() {
        arr[0] = 0;
        arr[1] = 1;

        for(int i=2; i<SIZE; i++) {
            arr[i] = arr[i-2] + arr[i-1];
        }
    }

    int& operator[](unsigned int i) {
        if (i >= SIZE) {
            std::cout << "(索引超过最大值) ";
            return arr[0]; // 返回第一个元素
        }
        return arr[i];
    }
};

int main()
{
    Fibo fb;
    
    for (int i=0; i<SIZE+1; i++) {
        cout << fb[i] << " ";
    }
    cout << endl;
    
    return 0;
}

编译和运行以上示例,输出结果如下:

0 1 1 2 3 5 8 13 21 34 (索引超过最大值) 0

示例 9:类成员访问运算符重载

C++ 允许重载类成员访问运算符(->),用于为一个类赋予 “指针” 行为。重载 -> 运算符时需要注意以下几点:

  • 运算符 -> 必须是一个成员函数;
  • 如果使用了 -> 运算符,返回类型必须是指针或者是类的对象;
  • 运算符 -> 通常与指针引用运算符 * 结合使用,用于实现智能指针的功能;
  • 这些指针是行为与正常指针相似的对象,唯一不同的是,通过指针访问对象时,它们会执行其它的任务(比如,当指针销毁时,或者当指针指向另一个对象时,会自动删除对象)。

间接引用运算符 -> 可被定义为一个一元后缀运算符,比如:

class Ptr{
   //...
   X * operator->();
};

Ptr 的对象可用于访问类 X 的成员,使用方式与指针的用法十分相似,如下:

void f(Ptr p )
{
    p->m = 10 ; // (p.operator->())->m = 10
}

语句 p->m 被解释为 (p.operator->())->m。通过下面示例加深理解:

#include <iostream>
#include <vector>

using namespace std;

// 假设一个实际的类
class Obj
{
    static int i, j;

public:
    void f() const { cout << i++ << endl; }
    void g() const { cout << j++ << endl; }
};

// 静态成员定义
int Obj::i = 10;
int Obj::j = 12;

// 为上面的类实现一个容器
class ObjContainer
{
    std::vector<Obj*> a;

public:
    void add(Obj* obj) {
        a.push_back(obj);  // 调用向量的标准方法
    }

    friend class SmartPointer;
};

// 实现智能指针,用于访问类 Obj 的成员
class SmartPointer {
    ObjContainer oc;
    int index;

public:
    SmartPointer(ObjContainer& objc)
    {
        oc = objc;
        index = 0;
    }
    // 前缀版本
    // 返回值表示列表结束
    bool operator++() 
    {
        if(index >= oc.a.size())
            return false;
        
        if(oc.a[++index] == 0)
            return false;
        
        return true;
    }
    // 后缀版本
    bool operator++(int)
    {
        return operator++();
    }

    // 重载运算符 ->
    Obj* operator->() const 
    {
        if(!oc.a[index]) {
            std::cout << "Zero value";
            return (Obj*)0;
        }

        return oc.a[index];
    }
};

int main() 
{
    const int sz = 6;

    Obj o[sz];
    ObjContainer oc;

    for(int i=0; i<sz; i++) {
        oc.add(&o[i]);
    }

    SmartPointer sp(oc); 

    do {
        sp->f(); 
        sp->g();
    } while(sp++);

    return 0;
}

编译和运行以上示例,输出结果如下:

10
12
11
13
12
14
13
15
14
16
15
17

示例 10:逻辑非运算符重载

逻辑非(!)运算符是一元运算符,它总是出现在所操作对象的左边,如 !obj。逻辑非运算符运算符返回的类型为 bool 类型,当对象为真值时,返回假;当对象为假值时,返回真。

下面示例演示如何重载 ! 运算符:

#include <iostream>
using namespace std;

class Rect
{
private:
    int width;
    int height;

public:
    Rect() {
        width = 0;
        height = 0;
    }

    Rect( int a, int b ) {
        width = a;
        height = b;
    }

    int area () {
        return width * height;
    }

    // 当 width 或者 height 有一个小于 0 则返回 true
    bool operator!() {
        if ( width <= 0 || height <= 0 ) {
            return true;
        }
        return false;
    }
};

int main()
{
    Rect r1(3, 4), r2(-3, 4);

    if (!r1) cout << "r1 is not a rectangle" << endl;
    else cout << "r1 is a rectangle" << endl;

    if (!r2) cout << "r2 is not a rectangle" << endl;
    else cout << "r2 is a rectangle" << endl;
    
    return 0;
}

使用 g++ main.cpp && ./a.out 命令编译和运行以上示例,输出结果如下:

r1 is a rectangle
r2 is not a rectangle

点击 GetIoT.tech 学习更多 C++ 编程知识!

有关十个 C++ 运算符重载示例,看完不懂打我...的更多相关文章

  1. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  2. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  3. ruby - 带括号和 splat 运算符的并行赋值 - 2

    我明白了:x,(y,z)=1,*[2,3]x#=>1y#=>2z#=>nil我想知道为什么z的值为nil。 最佳答案 x,(y,z)=1,*[2,3]右侧的splat*是内联扩展的,所以它等同于:x,(y,z)=1,2,3左边带括号的列表被视为嵌套赋值,所以它等价于:x=1y,z=23被丢弃,而z被分配给nil。 关于ruby-带括号和splat运算符的并行赋值,我们在StackOverflow上找到一个类似的问题: https://stackoverflow

  4. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

    我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

  5. ruby-on-rails - 看不懂Ruby的神奇 - 2

    在railscasts项目中你可以看到这段代码:before(:each)dologin_asFactory(:user,:admin=>true)end函数对应的定义是:Factory.define:userdo|f|f.sequence(:github_username){|n|"foo#{n}"}end我不明白admin参数是如何传递给函数的,而函数中没有关于admin参数的字样。谢谢 最佳答案 Factory.define不是一个函数定义,它是一个方法,它接受一个符号或字符串(在本例中是用户)和一个定义你正在制作的工厂的bl

  6. ruby - 定义自定义 Ruby 运算符 - 2

    问题是:除了在“OperatorExpressions”?例如:1%!2 最佳答案 是的,可以创建自定义运算符,但有一些注意事项。Ruby本身并不直接支持它,但是superatorsgem做了一个巧妙的把戏,将运算符链接在一起。这允许您创建自己的运算符,但有一些限制:$geminstallsuperators19然后:require'superators19'classArraysuperator"%~"do|operand|"#{self}percent-tilde#{operand}"endendputs[1]%~[2]#Out

  7. arrays - 如何在下面的示例中将两个值数组分组为 n 个值数组? - 2

    我已经有很多两个值数组,例如下面的例子ary=[[1,2],[2,3],[1,3],[4,5],[5,6],[4,7],[7,8],[4,8]]我想把它们分组到[1,2,3],[4,5],[5,6],[4,7,8]因为意思是1和2有关系,2和3有关系,1和3有关系,所以1,2,3都有关系我如何通过ruby​​库或任何算法来做到这一点? 最佳答案 这是基本Bron–Kerboschalgorithm的Ruby实现:classGraphdefinitialize(edges)@edges=edgesenddeffind_maximum_

  8. ruby - Google-api-ruby-client 翻译 API 示例 - 2

    很高兴看到google代码:google-api-ruby-client项目,因为这对我来说意味着Ruby人员可以使用GoogleAPI-s来完善代码。虽然我现在很困惑,因为给出的唯一示例使用Buzz,并且根据我的实验,Google翻译(v2)api的行为必须与google-api-ruby-client中的Buzz完全不同。.我对“Explorer”演示示例很感兴趣——但据我所知,它并不是一个探索器。它所做的只是调用一个Buzz服务,然后浏览它已经知道的关于Buzz服务的事情。对我来说,Explorer应该让您“发现”所公开的服务和方法/功能,而不一定已经知道它们。我很想听听使用这个

  9. ruby - Ruby 中 <=> 运算符的名称是什么?他们怎么调用它? - 2

    在Ruby中有运算符(operator)。在API中,他们没有命名它的名字,只是:Theclassmustdefinetheoperator...Comparableusestoimplementtheconventionalcomparison......theobjectsinthecollectionmustalsoimplementameaningfuloperator...它叫什么名字? 最佳答案 参见上面的@Tony。然而,它也被称为(俚语)“宇宙飞船运算符(operator)”。

  10. ruby - 将运算符传递给函数? - 2

    也许这听起来很荒谬,但我想知道这对Ruby是否可行?基本上我有一个功能...defadda,bc=a+breturncend我希望能够将“+”或其他运算符(例如“-”)传递给函数,这样它就类似于...defsuma,b,operatorc=aoperatorbreturncend这可能吗? 最佳答案 两种可能性:以方法/算子名作为符号:defsuma,b,operatora.send(operator,b)endsum42,23,:+或者更通用的解决方案:采取一个block:defsuma,byielda,bendsum42,23,

随机推荐