原文地址:  Click Here

操作符重载必须用public static 应为操作符是用来操作实例的。

operator

operator 关键字用于在类或结构声明中声明运算符。运算符声明可以采用下列四种形式之一:

  1. public static result-type operator unary-operator ( op-type operand )
  2. public static result-type operator binary-operator (
    op-type operand,
    op-type2 operand2
    )
  3. public static implicit operator conv-type-out ( conv-type-in operand )
  4. public static explicit operator conv-type-out ( conv-type-in operand )

参数:

  1. result-type 运算符的结果类型。
  2. unary-operator 下列运算符之一:+ - ! ~ ++ — true false
  3. op-type 第一个(或唯一一个)参数的类型。
  4. operand 第一个(或唯一一个)参数的名称。
  5. binary-operator 其中一个:+ - * / % & | ^ << >> == != > < >= <=
  6. op-type2 第二个参数的类型。
  7. operand2 第二个参数的名称。
  8. conv-type-out 类型转换运算符的目标类型。
  9. conv-type-in 类型转换运算符的输入类型。

注意:

  1. 前两种形式声明了用户定义的重载内置运算符的运算符。并非所有内置运算符都可以被重载(请参见可重载的运算符)。op-type 和 op-type2 中至少有一个必须是封闭类型(即运算符所属的类型,或理解为自定义的类型)。例如,这将防止重定义整数加法运算符。
  2. 后两种形式声明了转换运算符。conv-type-in 和 conv-type-out 中正好有一个必须是封闭类型(即,转换运算符只能从它的封闭类型转换为其他某个类型,或从其他某个类型转换为它的封闭类型)。
  3. 运算符只能采用值参数,不能采用 refout参数。
  4. C# 要求成对重载比较运算符。如果重载了==,则也必须重载!=,否则产生编译错误。同时,比较运算符必须返回bool类型的值,这是与其他算术运算符的根本区别。
  5. C# 不允许重载=运算符,但如果重载例如+运算符,编译器会自动使用+运算符的重载来执行+=运算符的操作。
  6. 运算符重载的其实就是函数重载。首先通过指定的运算表达式调用对应的运算符函数,然后再将运算对象转化为运算符函数的实参,接着根据实参的类型来确定需要调用的函数的重载,这个过程是由编译器完成。
  7. 任何运算符声明的前面都可以有一个可选的属性(C# 编程指南)列表。

explicit

explicit 关键字用于声明必须使用强制转换来调用的用户定义的类型转换运算符。

static explicit operator target_type { source_type identifier }

参数:

  1. target_type 目标类型
  2. source_type 源类型。
  3. identifier Something。

注意:

  1. 转换运算符将源类型转换为目标类型。源类型提供转换运算符。与隐式转换不同,必须通过强制转换的方式来调用显式转换运算符。如果转换操作可能导致异常或丢失信息,则应将其标记为 explicit。这可以防止编译器无提示地调用可能产生无法预见后果的转换操作。

implicit

implicit 关键字用于声明隐式的用户定义类型转换运算符。

static implicit operator target_type { source_type identifier }
注意:
  1. 隐式转换可以通过消除不必要的类型转换来提高源代码的可读性。但是,因为可以在程序员未指定的情况下发生隐式转换,因此必须注意防止令人不愉快的后果。一般情况下,隐式转换运算符应当从不引发异常并且从不丢失信息,以便可以在程序员不知晓的情况下安全使用它们。如果转换运算符不能满足那些条件,则应将其标记为 explicit。

示例:

以下是一个综合示例,简要展示用法。如要更具体细节的了解,请参阅MSDN Library。

// keywords_operator.cs
// keywords_operator.cs

using System;

namespace Hunts.Keywords
{
    // 定义一个人民币结构。数据类型转换的语法对于结构和类是一样的
    public struct RMB
    {
        // 注意:这些数的范围可能不能满足实际中的使用
        public uint Yuan;
        public uint Jiao;
        public uint Fen;

        public RMB(uint yuan, uint jiao, uint fen)
        {
            if (fen > 9)
            {
                jiao += fen / 10;
                fen = fen % 10;
            }
            if (jiao > 9)
            {
                yuan += jiao / 10;
                jiao = jiao % 10;
            }
            this.Yuan = yuan;
            this.Jiao = jiao;
            this.Fen = fen;
        }

        public override string ToString()
        {
            return string.Format("¥{0}元{1}角{2}分", Yuan, Jiao, Fen);
        }

        // 一些操作
        public static RMB operator +(RMB rmb1, RMB rmb2)
        {
            return new RMB(rmb1.Yuan + rmb2.Yuan, rmb1.Jiao + rmb2.Jiao, rmb1.Fen + rmb2.Fen);
        }

        public static implicit operator float(RMB rmb)
        {
            return rmb.Yuan + (rmb.Jiao/10.0f) + (rmb.Fen/100.00f);
        }

        public static explicit operator RMB(float f)
        {
            uint yuan = (uint)f;
            uint jiao = (uint)((f - yuan) * 10);
            uint fen = (uint)(((f - yuan) * 100) % 10);
            return new RMB(yuan, jiao, fen);
        }

        // more
    }
    class App
    {
        static void Main()
        {
            RMB r1, r2, r3, r4;

            // 记得小学时的某次捐款,我把口袋里藏好的一块钱加6张一毛钱以及13个一分钱的硬币都贡献出去了:(
            r1 = new RMB(1, 6, 13);
            // 其实当时其他人都已经交过了,他们总共交了:
            r2 = new RMB(46, 9, 3);
            // 那么加上我的就是:
            r3 = r1 + r2;
            Console.WriteLine("r3 = {0}", r3.ToString());

            // 隐式转换
            float f = r3;
            Console.WriteLine("float f= {0}", f);

            // 显式转换
            r4 = (RMB)f;
            Console.WriteLine("r4 = {0}", r4.ToString());
            //如果不进行显示转换,将出现错误 CS0266: 无法将类型“float”隐式转换为“Hunts.Keywords.RMB”。存在一个显式转换(是否缺少强制转换?)

            Console.Read();
        }
    }
}
/*
控制台输出:
r3 = ¥48元6角6分
float f = 48.66
r4 = ¥48元6角5分
*/

我们会发现r4结果少了一分钱!这是因为在:

uint fen = (uint)(((f - yuan) * 100) % 10);

这句中,在将float转换为uint时发生了圆整错误(这与计算机以二进制存储有关)。解决这个错误,我们可以使用System.Convert类中用于处理数字的静态方法:

uint fen = Convert.ToUInt32(((f - yuan) * 100) % 10);

不过使用System.Convert处理会有些性能的损失。

(一) operator、explicit与implicit 操作符重载的更多相关文章

  1. (二) operator、explicit与implicit 操作符重载

      有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成把两个整 ...

  2. C++一些注意点之操作符重载

    重载操作符需要注意 (1)重载操作符必须具有一个类类型操作数.不能重载内建类型的操作符. operator +(int,int);//这个是错误的,都为内建类型 operator +(int,clas ...

  3. C++解析(17):操作符重载

    0.目录 1.操作符重载 2.完善的复数类 3.小结 1.操作符重载 下面的复数解决方案是否可行? 示例1--原有的解决方案: #include <stdio.h> class Compl ...

  4. C++中操作符重载的概念

    1,下面的复数解决方案是否可行? 1,代码示例: class Comples { public: int a; int b; }; int main() { Complex c1 = {, }; Co ...

  5. 21.C++- "++"操作符重载、隐式转换之explicit关键字、类的类型转换函数

    ++操作符重载 ++操作符分为前置++和后置++,比如: ++a;  a++; ++操作符可以进行全局函数或成员函数重载 重载前置++操作符不需要参数 重载后置++操作符需要一个int类型的占位参数 ...

  6. operator、explicit与implicit

    说这个之前先说下什么叫隐式转换和显示转换 1.所谓隐式转换,就是系统默认的转换,其本质是小存储容量数据类型自动转换为大存储容量数据类型. 例如:float f = 1.0: double d=f:这样 ...

  7. [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)

    operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...

  8. C++ operator overload -- 操作符重载

    C++ operator overload -- 操作符重载 2011-12-13 14:18:29 分类: C/C++ 操作符重载有两种方式,一是以成员函数方式重载,另一种是全局函数. 先看例子 # ...

  9. 操作符重载operator

    发现一篇好文: 转载: http://www.cnblogs.com/xiehongfeng100/p/4040858.html #include <iostream>#include & ...

随机推荐

  1. python 小兵(10)内置函数

    内置函数(下午讲解) 什么是内置函数?就是python帮我们提供的一个工具,拿过直接用就行,比如我们的print,input,type,id等等.截止到python3.6.2版本 中一共提供了68个内 ...

  2. 从我做起[原生DI实现模块化和批量注入].Net Core 之一

    实现模块化注册 .Net Core实现模块化批量注入 我将新建一个项目从头开始项目名称Sukt.Core. 该项目分层如下: Sukt.Core.API 为前端提供APi接口(里面尽量不存在业务逻辑, ...

  3. ARC-124 部分题解

    E 直接统计原式不好做,注意到首先我们应该知道怎样的 \(x\) 序列是合法的,那么不妨首先来统计一下合法的 \(x\) 序列数量. 令 \(b_i\) 为 \(i\) 向右给的球数,那么有(\(i ...

  4. AtCoder AGC002 简要题解

    从今天开始,联赛之前大约要完成前 \(20\) 套 \(\rm AGC\),希望不要鸽. A 略 B 感觉这题比 \(\rm C\) 题难. 考虑对于每个时刻维护每个位置是否可能出现红球,那么一个时刻 ...

  5. Java基础之Scanner类中next()与nextLine()方法的区别

    java中使用Scanner类实现数据输入十分简单方便,Scanner类中next()与nextLine()都可以实现字符串String的获取,所以我们会纠结二者之间的区别. 其实next()与nex ...

  6. C语言中的单引号和双引号的区别

    首先肯定地说,二者是有区别的,不是说用谁都一样. 1.实质区别,代表的含义不同 'A'代表的是一个整数,而且这个整数对应的是编译器所采用的字符集中的字符序列对应的数值.所以'A'跟ASCII中的65意 ...

  7. KubeSphere单节点(all-in-one)平台搭建记录

    KubeSphere单节点(all-in-one)平台搭建记录 目录 KubeSphere单节点(all-in-one)平台搭建记录 一.主机准备 1.1 主机配置 1.2 环境准备 二.下载kube ...

  8. 【HDU6662】Acesrc and Travel(树型Dp)

    题目链接 大意 给出一颗树,每个点上有一个权值\(A[i]\),有两个绝顶聪明的人甲和乙. 甲乙两人一起在树上轮流走,不能走之前经过的点.(甲乙时刻在一起) 甲先手,并可以确定起点.甲想要走过的点权之 ...

  9. 模型融合——stacking原理与实现

    一般提升模型效果从两个大的方面入手 数据层面:数据增强.特征工程等 模型层面:调参,模型融合 模型融合:通过融合多个不同的模型,可能提升机器学习的性能.这一方法在各种机器学习比赛中广泛应用, 也是在比 ...

  10. pytest(8)-参数化

    前言 什么是参数化,通俗点理解就是,定义一个测试类或测试函数,可以传入不同测试用例对应的参数,从而执行多个测试用例. 例如对登录接口进行测试,假设有3条用例:正确账号正确密码登录.正确账号错误密码登录 ...