原文地址:  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. redis实现简易在线聊天室

    redis_flask简易聊天室 项目构建 这时一个基于Redis数据库的简单小项目,使用redis缓存数据,并通过flask部署到浏览器,运行截图如下: 输入名字后,就可以登陆到聊天室,主要包括三个 ...

  2. Spring Boot Starter 和 ABP Module

    Spring Boot 和 ABP 都是模块化的系统,分别是Java 和.NET 可以对比的框架.模块系统是就像乐高玩具一样,一块一块零散积木堆积起一个精彩的世界.每种积木的形状各不相同,功能各不相同 ...

  3. python 爬虫爬取历年双色球开奖信息

    目前写的这些爬虫都是些静态网页,对于一些高级网页(像经过JS渲染过的页面),目前技术并不能解决,自己也是在慢慢学习过程中,如有错误,欢迎指正: 对面前端知识本人并不懂,过程中如果涉及到前端知识,也是百 ...

  4. python26day

    内容回顾 多态: ​ 一个类表现出的多种形态,实际上是通过继承来完成的 今日内容 super,调用父类的同名方法 按照mro顺序来寻找当前类的下一个类 封装 广义上的封装 方法属性名字前加了__,就变 ...

  5. python 单元测试 执行测试

    1.在unittest框架中执行测试用例: if __name__ == "__main__": unittest.main() # unittest框架会把以test_开头的实例 ...

  6. python 小兵内置函数进制转换

    Python内置函数进制转换的用法 使用Python内置函数:bin().oct().int().hex()可实现进制转换. 先看Python官方文档中对这几个内置函数的描述: bin(x)Conve ...

  7. webpack搭建react+ts+eslint项目

    [初始化项目] mkdir react_ts_eslint cd react_ts_eslint npm init [生成ts配置文件] tsc --init [安装相关依赖] npm install ...

  8. 线程池与Callable接口

    定义: 一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源. 使用方法 public void lockDemo() throws Inter ...

  9. 用最笨的方法实现java控制台日历打印

    如果想用户自定义输入日期查询,可以通过Calendar的set方法和Scanner方法设置 Calendar类简单使用:https://blog.csdn.net/weixin_43670802/ar ...

  10. php导出excel xml word

    转载请注明来源:https://www.cnblogs.com/hookjc/ Excel: <?php header("Content-Type: application/vnd.m ...