原文地址:  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. gin框架中图形验证码的生成和验证

    功能和验证码使用原理 本案例中没有使用redis作为缓存,而是使用的内存存储方法 github链接地址 下载命令 go get github.com/mojocn/base64Captcha 请求处理 ...

  2. Selenium&PhantomJS 完成爬取网络代理

    Selenium模块是一套完整的Web应用程序测试系统,它包含了测试的录制(SeleniumIDE).编写及运行(Selenium Remote Control)和测试的并行处理(Selenimu G ...

  3. 网页中的一键加QQ群、唤起QQ群聊天窗口

    1.进入QQ群官网: https://qun.qq.com 2. 登陆QQ账号,点击加群组件 3. 左侧选择指定的群,右侧会给出一键加群的链接 4. 浏览器访问刚才复制的链接,点击 打开腾讯QQ 5. ...

  4. (2)RabbitMQ架构设计与应用场景

    1.什么是消息中间件? 消息是指应用间传输的数据.消息体包括文本字符串.Json.内嵌对象等.消息中间件是基于队列模型实现异步和同步传输数据的.作用:解耦,冗余(存储).扩展性.削峰.可恢复性.顺序保 ...

  5. 图文并茂理解iptables

    原文地址:http://www.zsythink.net/archives/1199 以下是转载内容: iptables详解:图文并茂理解iptables | 朱双印博客 这篇文章会尽量以通俗易懂的方 ...

  6. python使用制表符或者换行符来添加空白--3

    #!/usr/bin/python #coding=utf-8 message="python" print(message) print("\tpython" ...

  7. AT2043 [AGC004C] AND Grid

    首先可以发现一个很简单的想法,因为最外层是一定不会有 \(\#\) 的,所以可以考虑让第一个网格图将每个连通块的最外层包起来,第二个网格图将就选择这个包内部的所有点即可. 但你发现这个想法是很难实现的 ...

  8. Redis sentinel.conf配置文件详解

    redis-sentinel.conf配置项说明如下: 1.port 26379 sentinel监听端口,默认是26379,可以修改. 2.sentinel monitor <master-n ...

  9. mac os 利用ssh 搭建git server服务器详细教程,以及git基本用法

    详细讲mac 连接mac的git操作 首先在服务端上 第一:新建一个仓库 1, cd /Users/userName/projects 用linux命令进入一个你想要创建与他人共享的文件夹. 2,su ...

  10. 【译】System.Text.Json 的下一步是什么

    .NET 5.0 最近发布了,并带来了许多新特性和性能改进.System.Text.Json 也不例外.我们改进了性能和可靠性,并使熟悉 Newtonsoft.Json 的人更容易采用它.在这篇文章中 ...