zoukankan      html  css  js  c++  java
  • [置顶] C++重载运算符详解

    ↑有些东西或许大家已经知道,请使用目录↑

    结构体基础

    结构体,是一种可以自己编写数据类型(如int,double等)的一种数据集合,声明关键字struct,框架(声明于main之外):

    struct 名称
    {
        集合之中的变量
    };//分号一定不要忘了

    例如:

    struct student
    {
        char name[10];
        int grade,num,age;
    };

    这样你就成功定义了一个“student”类型的数据集合,这意味着你可以这样用:student Bob;
    你也可以在结构体的最后加上你想定义的数据集合名称,如:

    struct student
    {
        char name[10];
        int grade,num,age;
    }Bob;

    于是就有了一个名叫Bob的变量集合,它里面包含有Bob的name,grade和age;
    但是,可能已经有人注意到了,上文“Bob的”中的“的”怎么使用呢?
    于是有了一个运算符:.,它叫做成员运算符,也是一会会提到的少数几个不能重载的运算符之一,它的用处在于访问一个结构体集合中的变量(即成员变量),如:Bob.age=13;然后Bob这个集合中的年龄就被赋为了13。
    当然,结构体之间是可以相互赋值的,这样里面的每一个成员变量都会被赋值。

    结构体函数

    结构体中不仅可以有成员变量,也可以有成员函数。

    一般函数

    这个很简单,在成员函数中你可以使用你的成员变量,当你需要访问自己这个结构体时,需要一个特殊的指针:*this,对于这个最通俗的解释是:你在一个房子(结构体)里装修,你需要看到或改变房子的外部,就用*this(在讲重载运算符实会用到),框架:

    struct 名字
    {
        成员变量
        成员函数类型 成员函数名称(参数)
        {
            函数体
        }
    };

    你会发现,在结构体里写函数和在外面写是基本一样的,例子:

    struct Number
    {
        int a,b;
        int max(){return a>b?a:b;}
        int add(){return a+b;}
        void clean(){a=b=0;}
    };

    可以这样用:

    Number A;
    scanf("%d%d",&A.a,&A.b);
    printf("The biger one:%d.
    Their sums:%d",A.max(),A,add());
    A.clean();

    构造函数

    构造函数是在定义结构体变量时自动调用的函数,用于对结构体成员初始化。
    结构体原本是包含一个默认构造函数的,它没有参数,函数体也为空,你可以修改这个函数的函数体,但参数列表必须为空。
    你也可以写其他构造函数,但参数的个数或参数类型必须不同,C++将根据实际情形选择最合适的构造函数去调用。
    如果你没有增加构造函数,也没有修改默认构造函数,默认构造函数便可以省略,但如果你自己定义了构造函数,则默认构造函数必须写上。
    也就是说你可以这样写:

    struct num
    {
        int len,a[100];
        num(){len=0;memset(a,0,sizeof(a));}
    }

    当你num A时,A里面的len和a都被清零了。

    重载运算符

    重载运算符有什么用呢?最常用的是高精度运算,以前我们经常用数组来写高精度,有了重载运算符和结构体后,就意味着你的main函数中只需要这样写:

    Bignum A,B,C;
    A.read();
    B.read();
    C=A+B;
    C.print();
    C=A*B;
    C.print();

    是不是很爽。
    这里就用高精度(当然不涉及压位,要压位的自己改改即可)来举例子,具体的写法这里不会写,大家直接百度高精度就可以了。

    规则

    重载是有规则的,首先,“重载运算符”是“重载”,而不是“定义”,所以你只能改变一个C++中已有的运算符,而不是定义一个本来没有的运算符,如果你真的想这样,请搜索define。
    1.C++只能重载C++中已有的运算符;除了少数几个运算符不能重载外,全部可以重载,不能重载的操作符是类属关系运算符”.”、成员指针运算符“*”(当这个作乘号时是可以重载的,你不用在意编译器的想法~)、作用域分辨符“::”和三目运算符“?:”。
    2.重载运算符后的优先级和结合性都不会改变。
    3.重载的运算符要与该运算本身的含义一致,不能导致混乱。
    注意:重载运算符时,其参数个数比实际上参与运算的个数少一个。因为该对象自身也将参与运算。
    如果以上规则不容易看懂,下面会有例子。

    框架

    具体还是要看例子

    重载类型 operator/*这是一个重载运算符的关键字*/ 重载符号(参数)
    {
        要执行的内容
        return X;//返回一个值(void则不用返回)
    }

    赋值重载

    不用想都知道,肯定不能直接这样写:

    int a;
    Bignum A;
    A=a;

    所以我们要重载=使它不再只适用于相同类型变量间的赋值,而是用于将int类型赋给Bignum类型:

    struct Bignum
    {
        int len,a[MAXN];//这个高精数的长度和值
        Bignum(){len=0;memset(a,0,sizeof(a));}
        void/*赋值是一个不需要返回值的操作*/ operator =(int x)/*这里的参数实际上是你等号后面的东西,等号前面只能Bignum类型,也就是说,只能写成'Bignum = int'的格式才会执行以下内容*/
        {
            char t[MAXN];
            sprintf(t+1,"%d",x);//用于把一个变量按位存入char数组,t+1,指针后移一位,这样就会从1开始存
            len=strlen(t+1);//这里的len是成员变量len
            for(int i=1;i<=len;i++)
                a[i]=t[len-i+1]-'0';//高精度倒着存
        }
    }

    关系运算符重载

    这里要重载的十分多:>,>=,<,<=,==…那么是不是要一一写呢?答案是否定的,实际上你只需要写出一个<重载,然后其他运算符都可以用逻辑运算和已经重载的<表示出。
    例如判断>=X可以这样写:return !(*this<X);前面有讲过*this。
    想想,其他关系运算符可以怎样表示呢?
    代码:

    bool/*不难理解,只有是或不是两种关系*/ operator <(Bignum x)//两个Bignum之间的比较
    {
        if(len!=x.len) return len<x.len;
        for(int i=len;i>=1;i--)
            if(a[i]!=x.a[i]) 
                return a[i]<x.a[i];
        return false;//相等也是false
    }
    bool operator > (BIGNUM &x) {return x<*this;}//事实上反过来比较就是>了
    bool operator <= (BIGNUM &x) {return !(x<*this);}
    bool operator >= (BIGNUM &x) {return !(*this<x);}
    bool operator == (BIGNUM &x) {return !(x<*this||*this<x);}
    bool operator != (BIGNUM &x) {return x<*this||*this<x;}//这些很容易理解

    同样把上面的放在结构体中即可。

    算术运算符重载

    这个就要一个一个写了,除了加减乘除模,你甚至可以写一个开方乘方(可以随便找一个符号重载,如|,^),这是算法的事情,我们不说。相信经过前面的代码,大体实现大家已经明白,这里再写一个加法:

    BIGNUM/*因为我们用到的结构是'Bignum = Bignum + Bignum',而且我们没有重载其他用法的'=',所以右边的'Bignum + Bignum'应该是返回一个Bignum,才能赋给最前面的Bignum*/ operator + (BIGNUM x)
    {
        BIGNUM c;
        c.len=max(len,x.len)+1;
        for(int i=1,p=0;i<=c.len;i++)
        {
            c.a[i]=a[i]+x.a[i]+x;//a[i]为这个结构体的成员变量,x.a[i]是x的成员变量
            p=c.a[i]/10;
            c.a[i]%=10;
        }
        if(c.s[c.len-1]==0) c.len--;
        return c;//返回结果
    }

    输入输出

    这个非常简单,成员函数void print()void read(),里面高精度该怎么读怎么读即可。

  • 相关阅读:
    java程序员从ThinkPad到Mac的使用习惯改变
    关于mybatis缓存配置详解
    log4j每天,每小时产生一日志文件
    $_SERVER常用
    curl抓取页面时遇到重定向的解决方法
    十三)CodeIgniter源码分析之Loader.php
    十二)CodeIgniter源码分析之Model.php
    十一)CodeIgniter源码分析之Controller.php
    十)CodeIgniter源码分析之Output.php
    九)CodeIgniter源码分析之Hook.php
  • 原文地址:https://www.cnblogs.com/LinqiongTaoist/p/7203727.html
Copyright © 2011-2022 走看看