这是一篇晦涩难懂的片面的研究

一,简单的继承层次

    class CA {
}
class CB : CA{
}
class CC : CB{
}
}
void Test(CA oa){//CATest
Debug.Log ("CA===============");
}
void Test(CB oa){//CBTest
Debug.Log ("CB===============");
}
void Test(CC oa){//CCTest
Debug.Log ("CC===============");
} //测试代码如下:
CC oc = new CC ();
Test (oc);

在这种情形下调用Test(oc)有如下规律:<通过注释掉其它函数进行测试>

  1. 若CATest , CBTest, CCTest三个重载函数都存在,则Test(oc)将调用CCTest
  2. 若只有CATest, CBTest二个重载函数,则Test(oc)将调用CBTest
  3. 若三个函数只有一个存在,则Test(oc)即调用该函数。

由此我们得知,Test(oc)调用时,编译器会由oc的继承层次由子到父的优先级去匹配重载函数的形参。这也符合正常逻辑。

二,类中有运算符重载的继承

   class CA {
}
class CB : CA{
}
class CC : CB{
/* MSDN类型转换的要求
1.操作数必须是封闭类型
2.类A到类B的类型转换定义不能在类C中进行(即2个类的转换不能在第3个类中定义, 如下面的参数定义)*/
public static implicit operator bool(CC ot/*不能是CA ot或 CB ot */){
Debug.Log ("bool================");
return ot != null;
}
}
void Test(CA oa){//CATest
Debug.Log ("CA===============");
}
void Test(CB oa){//CBTest
Debug.Log ("CB===============");
}
void Test(CC oa){//CCTest
Debug.Log ("CC===============");
}

   void Test(bool b){//boolTest
     Debug.Log ("b===============")
   }
//测试代码如下:
CC oc = new CC ();
Test (oc);

此情形下boolTest重载函数和CATest, CBTest, CCTest的任何一个重载都冲突,原因如下:

当调用Test(oc)时,编译系统将oc与Test的四个重载函数的参数进行匹配,却发现四个都能匹配成功。Test(bool b)通过CC类的bool类型符重载而匹配。

CATest, CBTest, CCTest三个重载函数由于形参CC,CB,CA是继承关系,在进行匹配时是有优先级的,由于ot是CC类型的,所以优先级CC>CB>CA,因此这个三个重载函数间没有冲突,编译器明确知道该调用哪个重载。而bool重载与CC,CB,CA在类型转换时是同优先级,因此编译系统不知道该调用bool重载还是CC,CB,CA的三个重载了。

若将bool重载由类CC移到类CA中,其它代码不变,测试代码不变。经测试,boolTest,CATest, CBTest, CCTest四个重载可以共存,即boolTest与其它任何一个重载都不冲突。

  1. boolTest,CATest, CBTest, CCTest同时存在,Test(oc)调用了CCTest
  2. boolTest,CATest, CBTest同时存在,Test(oc)调用了CBTest
  3. boolTest, CATest同时存在,Test(oc)调用了CATest
  4. boolTest,CATest, CBTest, CCTest只有一个存在,则调用此存在
  5. 只有boolTest存在时,该重载函数也被调用

这说明了基类的类型重载运算符的调用优先级低于父子层级转换的优先级,如情形5,在只有bool重载运算符时才会被调用。

本类的类型重载运算符的优先级等于父子层次转换的优先级。

三,Unity中的调用

UnityEngine所有类的的基类都是UnityEngine.Object。这个类与System.Object的关系很诡异。

System.Object obj = new UnityEngine.Object() //这行代码在编译上没问题,其实非常诡异,后面单独说

这样写可以正常编译。反过来将System.Object赋予UnityEngine.Object则不能编译通过。

这似乎可以说 System.Object 是 UnityEngine.Object的基类,网上许多人也这么认为。还有人说是隐式继承。

然而,通过看U3D的API,可以看到UnityEngine.Object并没有继承任何类,UnityEngine的源码中Object也确实没有继承任何类。这只能说是CLR内部自己的搞的鬼。

于是在这种情形下,重载函数的调用规律就有了一点小的改变。

这就是:UnityEngine.Object类及子类适用于上面的规律。而System.Object则处于所有类型的最低优先级,低于bool类型转换重载。例:

public class NewBehaviourScript : MonoBehaviour {
void OTest(bool b){//F1
Debug.Log ("OTest--b-");
}
void OTest(System.Object obj){//F2
Debug.Log ("OTest-system-obj-");
}
void OTest(UnityEngine.Object obj)//F3
{
Debug.Log ("OTest-obj");
}
void OTest(Transform tran){//F4
Debug.Log ("OTest-trans-");
} void Start (){
OTest (gameObject.transform);
} void Update () {
}
}

调用优先级F4>F3>F1>F2。即:

  1. F1,F2,F3,F4共存时,OTest (gameObject.transform)调用F4,因F4形参为Transfrom类型,与实参相同,接近度最高。
  2. 若仅有F1,F2,F3共存,OTest (gameObject.transform)调用F3,因F3形参为UnityEngine.Object类型,是实参类型Transfrom的直接父类,接近度最高。
  3. 若仅F1,F2共存,因System.Object只是UnityEngine.Object的隐式父类,在语法上已不是其父类了,这时编译器会试着寻找bool类型重载,结果找到了。
  4. 若仅F2存在,编译器既没找到可用的直接转换,也没找到bool重载,于是就剩下隐匿父类可以尝试了,于是调用F2。

当仅有F1,F2共存时,大多数人的直觉是:OTest (gameObject.transform)肯定会调用F2: OTest(System.Object obj),网上有些同学很早发现了这个诡异现象

附:System.Object obj = new UnityEngine.Object() 这个诡异问题。

  1. new 一个UnityEngine.Object的对象是不合语义的,可以看到Unity API中的描述:Instatiating a GameObject adds it to the scene so it's completely initialized (!destroyed). Instantiating a simple UnityEngine.Object has no such semantics, so the it stays in the 'destroyed' state which compares true to null
  2. UnityEngine.Object obj = new UnityEngine.Object() //null 这行代码的结果是obj为null,如1中所述。然而 
  3. System.Object obj = new UnityEngine.Object() //诡异在这里,调试数据如下

可以看到suo 与 uo的调试数据都是 {null},这大概就是表示对象为空吧,if(uo==null)成立,输出了 uo==null字符串,然而if(suo==null)却不成立!!对于神奇的.NET,我只能说:用unity时就别用system.Object了。

C# 类型运算符重载在类继承中的调用测试的更多相关文章

  1. C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 对运算符重载的函数有两种处理方式:(1)把运算符 ...

  2. 运算符重载+日期类Date

    Hello,一只爱学习的鱼 大学学习C++运算符重载的时候,老师出了一道"运算符重载+类"的综合练习题,让我们来一起看看吧! 题目: 设计一个日期类Date,包括年.月.日等私有成 ...

  3. C# 类继承中的私有字段都去了哪里?

    最近在看 C++ 类继承中的字段内存布局,我就很好奇 C# 中的继承链那些 private 字段都哪里去了? 在内存中是如何布局的,毕竟在子类中是无法访问的. 一:举例说明 为了方便讲述,先上一个例子 ...

  4. C++类继承中的构造函数和析构函数 调用顺序

    思想: 在C++的类继承中,构造函数不能被继承(C11中可以被继承,但仅仅是写起来方便,不是真正的继承) 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时, ...

  5. (C++)C++类继承中的构造函数和析构函数

    思想: 在C++的类继承中, 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时,其顺序正好与构造相反: 例子: #include <iostream& ...

  6. C++ 类的继承四(类继承中的重名成员)

    //类继承中的重名成员 #include<iostream> using namespace std; /* 自己猜想: 对于子类中的与父类重名的成员,c++编译器会单独为子类的这个成员变 ...

  7. C++ 类的继承五(类继承中的static关键字)

    //类继承中的static关键字 #include<iostream> using namespace std; /* 派生类中的静态成员 基类定义的静态成员,将被所有派生类共享 根据静态 ...

  8. C++学习6-面向对象编程基础(运算符重载、类的派生与继承、命名空间)

    运算符重载 重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.重载的运算符是遵循函数重载的选择原则,根据不同类型或不同参数来选择不同的重载运算符. 运 ...

  9. C++基础——类继承中方法重载

    一.前言 在上一篇C++基础博文中讨论了C++最基本的代码重用特性——类继承,派生类可以在继承基类元素的同时,添加新的成员和方法.但是没有考虑一种情况:派生类继承下来的方法的实现细节并不一定适合派生类 ...

随机推荐

  1. iOS仿京东分类菜单实例实现

    在APP开发过程中此功能还是比较常见的模块,左边为菜单展示,右边为菜单下数据的展示,选择不同的菜单右边的数据源进行更新,此实例主要运用到UITableView,UICollectionView,OC谓 ...

  2. git 查看远程分支、本地分支、删除本地分支

    1 查看远程分支 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ git branch -a   * br-2.1.2.2   master   remotes/origi ...

  3. Eclipse下快速打开本地文件的插件easy explore

    插件下载地址:http://jianguoyun.com/p/DeNpa8IQx5jkBRjKlAk 放到eclipse的plugin目录下后,eclipse 3.5+可以放到dropins目录下,重 ...

  4. 团队管理_效率开会[持续更新ing]

    1.明确开会目的,这个会议是用来解决什么问题,得出什么结果. 2.明确会议内容与流程,简要说明会议分几个部分,一步一步推进会议的进行. 3.保证参会人员守时参加,会议准时开始. 4.保证会议时间尽量为 ...

  5. 3.输入三个整数,xyz,最终以从小到大的方式输出。利用嵌套。

    <body>请输入a的值:<input type="numbe" id="a" value=""/>请输入b的值:& ...

  6. 深入探讨 Java 类加载器

    转自:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器(class loader)是 Java™中的一个很重要的概念.类 ...

  7. 在VS2010中使用Outlook工具栏

    参考资料:微软MSDN.VS2010示例代码 一开始上段子总是能活跃气氛,等哪天我再打开自己的这篇博客,总是能够让自己傻傻的乐一下. 我一女同学,毕业去一大公司应聘,竞争很激烈,最后剩下她和一位女士. ...

  8. cd dirname $0

    这个命令的功能是返回脚本正在执行的目录. 可以根据这个目录来定位运行的程序的相对位置. 这样,对shell脚本里面的相对目录的路径代码就比较安全了.在任何一台服务器上面都可以安全执行.

  9. oracle树操作(select start with connect by prior)

    oracle中的递归查询可以使用:select .. start with .. connect by .. prior 下面将会讲述oracle中树形查询的常用方式,只涉及到一张表. 一. 建表语句 ...

  10. td内元素居顶,td元素不随高度的撑开而变位置

    如下图,右边内容变高了,左边元素位置就下降到居中 设置居顶不变的方法 <table width="200" border="1"> <tr&g ...