类型,转换,数组,协变及其他

为了让叙述简化,先定义几个用到的术语:

函数:可以给出输出的那种抽象体,变量可以认为是无参数函数。对于成员函数或者更习惯的叫做方法的那种函数,我认为它就是隐含了对象参数的函数。

类型系统是现在OO语言的核心和基石。类型系统是保证正确性的基础,现在的编程语言大多强调静态安全性,其实就是编译时类型正确性。动态类型系统对应着运行期类型检查,保证运行时的类型正确性。经常所说的安全性其实就是类型正确性。

类型转换是对类型系统的公然藐视。它不是安全的。可能会引入很多问题。有时候,我们可能会觉得需要类型转换,但是那是错觉,我们可以定义一个函数,接受某种类型的对象,返回另一种类型的对象。所以类型转换是不必要的。有人会说,你把类型转换看成某种形式奇怪的函数调用得了。我承认,这个想法很好,但是有两个缺陷,一、类型转换比函数更强横霸道,能干很多函数不能干的事。二、类型转换有时候会自动发生。

数组,一个常见的语言构造,大多数语言都支持它。它一般被定义为同一类型的一堆对象,可以通过index来认领这一堆对象中的任意一个。很多语言都把这一堆对象起一个名字,同时通过[index]运算认领。但是,有很多语言都不支持数组作为一个一类构造。原因是他们认为:数组也不过是一个对象而已,它包含多个其他对象,这种包含多个其他对象的对象一般叫做容器。还有另一种观点是,数组不外是函数而已。它完成一个从index到对象的映射。不管是哪种观点,都比原始的数组的观念强大,更容易加上一些辅助的特性如边界检查什么的。当然,这似乎暗示引入[]是无价值的。()就行了。嘻嘻,BASIC啊。

单单静态类型检查是不够的。最常见的一个例子是list,如果我们要求必须是静态检查,那么有可能要求我们要么放宽list容器容纳的对象类型(也就是通用化、泛化(这是根特化和继承相对的那个概念,不要联系到泛型)),要么强大的限制了list的能力。举例吧:一个list,在它的偶数位置放置鹦鹉,奇数位置放置大象,如果是完全的静态类型检查,那么我们可能会说:我们有一个放置动物的list,但是这容易造成我们放了一只蚂蚁进去!而且类型系统不能够阻止这个行为。实际上造成了不正确性。

协变(Covariance)、抗变(Contravariance)和不变(Nonvariance)是OO理论中最容易引起争论的话题。不过它们是如此重要和基本,非说不可了。它们跟继承多态什么的密切相关。同时,它们也会涉及到如何搞定上面提到的list的问题。

所谓协变,就是随同主类型一起变化。故此称为“协”。还是举例说明比较清楚:

class Animal
{
public:
marry(Animal another);
};

class Elephant : public Animal
{
public:
marry(Elephant another);
};

class Fox : public Animal
{
public:
marry(Fox another);
};

其中,marry的参数another就是协变的。大家可能觉得,咦,这不是挺好么?其实,对于参数的协变还有很多别的说法。就一般情况而言,大多数人认为,参数应该是抗变的,那么,什么是抗变呢?抗变,又叫反变,意思是说,子类型的函数参数应该是父类型的函数参数的父类型,这儿稍微有点绕,仔细看清楚了,呵呵,等你理解了这句话,你会觉得这不符合直觉,对吗。可是,事实上,这句话是对的,在一般意义上是对的。我举个例子:

你是一个打印服务供货商,你向客户承诺,可以接受TXT和PS格式的文件,返回一堆打印纸张,拥有TXT或者PS文件描述的内容。

后来,你想升级换代,你又增加了一种文件格式PDF,你没有错,你可以赢得新的客户,但是如果你说我要取消TXT文件格式,那么,你的客户可能会抱怨你的。也就是说,你只能放宽你接受的参数类型(泛化、父类什么的),但是变窄(特化、子类什么的)会导致原来能够正常工作的东西突然失效。

现在你或许觉得参数抗变是合理的,应该的。可是别急,想想前面的例子,难道说,动物和动物结婚没错,大象和应该和动物或者更上层的类生物结婚么?是啊,这是一个问题,你或许会觉得这可能是个特例,但实际上这是普遍存在的,回想一下我们的成员函数(方法),就会发现,该函数有一个隐含的this参数一直就是协变的。另外,函数的返回值类型也是协变的,这个几乎没有争议。就如同上面那个例子,你给你的客户是一堆打印了内容的纸,如果你改成它的子类,一堆打印了内容的好纸,你的客户不会反对的。对于变量,我说过它也不过是没有参数的函数的返回值,那么这儿似乎暗示它们应该是协变的。

还有更复杂的问题。比如我们上面那个动物类型体系,我们有一个叫做吃的函数,动物吃食物,大象吃草,狐狸吃肉。这个该算做什么?协变吧。这么说,我们没有办法决定究竟该怎么弄了?究竟怎么回事?继续看:)

现在介绍一个概念,分派(Dispatch)。分派其实就是函数调用。不过稍微有点复杂的是:它根据它的参数类型来选择特定的函数实施这个调用。

Motor* m = new ...();
m->run();

这个run就是一个函数。究竟调用那一个run,依赖于m这个参数(m其实就是那个隐含的this参数)的实际类型,这就是分派。很明显,我们这个是OO 里面多态的基础,另外还有一个术语叫做双分派,其实就是根据两个参数来决定调用那个函数,当然,推而广之就有多分派这个说法了。

某位大牛(记不得叫什么了,抱歉啊)经过研究最终发话了:一个函数中,那些决定分派的参数应该是协变的,而其他的参数应该是反变的。看到这儿,手抚额头,恍然大悟啊。原来如此,就应该如此,非如此不可啊。呵呵。

上面啰里啰唆说了一大通,发现没有提到动态类型相关的东西,现在说说吧。C++里面关于动态类型的构造叫做RTTI——运行时类型信息。关于这个的有两个操作,一个叫做dynamic_cast<T*>(pO),一个就是臭名昭著的typeid了。第一个操作是在运行时得到实际的类型信息,当然,有可能失败的。比如:一个动物,其实际类型是蚂蚁,但是我在运行时想通过dynamic_cast变换成大象,这个肯定不可能。但是我们可以进行这种尝试,如果失败,我们也能得到某种信息不是吗。对于typeid,我就不说别的了,它的增强版就是typeof,其实也就是所有支持反射的语言的基本机制,这个东西一般被认为是不合规矩的:),但它确实在某种程度上增加了我们的表达能力。
SPSS实战:5步搞定多指标联合诊断的ROC曲线分析(附Logistic回归教程) 本文详细介绍了如何使用SPSS软件进行多指标联合诊断的ROC曲线分析。通过5个实战步骤,从数据准备、二元Logistic回归建模生成综合预测概率,到绘制并比较单指标与联合模型的ROC曲线,帮助临床研究者有效整合多个诊断指标,提升模型判别能力(AUC),实现诊断效能的优化。 阅读详情

相关推荐

遥感新手别纠结!实测ENVI 5.3、5.6、6.0三个免费版,教你混搭安装避坑

本文为遥感新手提供ENVI 5.3、5.6、6.0三个免费版的实测对比与混搭安装指南,帮助用户构建零成本高效工作流。详细解析各版本功能差异、共存安装技巧及常见问题解决方案,特别适合课程作业、毕业论文分析和遥感入门练习。

weixin_30819085的博客 474

java 数组协变

在某些情况下,即使某个对象不是数组的基类型,我们也可以把它赋值给数组元素。这种属性叫做协变(covariance)。在下面的情况下可以使用协变:数组是引用类型数组。在赋值的对象类型和数组基类型之间有隐式转换或显式转换。由于在派生类和基类之间总是有隐式转换的,因此总是可以将一个派生类的对象赋值给为基类声明的数组。只有数组存在协变,此功能有利也有弊,相对于List 是支持泛型 不支持协变class A...

weixin_30458043的博客 540

QMT量化交易桥接方案深度对比:从MiniQMT淘汰说起

量化交易系统中的API桥接,本质是解决本地终端与底层交易引擎之间的通信瓶颈。其核心原理在于绕过GUI封装、直连确定性执行层,从而获得低延迟、高可靠、可监控的指令通路。技术价值体现在策略实盘一致性提升、毫秒级响应保障及运维可控性增强。典型应用场景包括打板策略、T+0套利、高频网格等对时效与稳定性双敏感的自动化交易。本文聚焦国金证券QMT专业版生态,系统剖析DLL注入、HTTP反向代理、IPC共享内存与官方HTTP API四大桥接路径的性能边界、合规风险与工程落地成本,尤其深入解析qmt终端 client is

weixin_33892359的博客 457

Java 学习笔记 - 数组类型互转

测试数据 字符串数组 to (Integer、Long、Double)列表 传统方式 1.【String数组】转成【Long数组】 2.【Long数组】 转 【ArrayList】 Java8 Stream方式 数组 to 数组 字符串数组 to (int、long、double )数组 int[]、long[]、double[] 数组互相转换 int[]、long[]、double[] 数组再转回 String[] 基础类型数组 to 列表 int数组 to 列表 long数组 to 列表 d

灵台方寸山斜月三星洞 2万+

SAP接口错误查询日志

随着数字经济的迅速发展,企业数字化转型不在只追求“业财一体化”,而是在业务端也想要进行更为精细化的管理,所以很多企业在SAP ERP的基础上,集成更多垂直领域更精细的外围系统,比如销售CRM系统,采购SRM系统,生产MES系统等等,琳琅满目的产品,那对SAP实施来说,系统集成过程中,接口的一些报错查询能力必不可少,今天我们就介绍一下,SAP和CRM系统集成中接口常见的报错。

weixin_43657667的博客 2049

S7-1200PLC期末复习题(第七章)

A.0 B.1 C.4 D.-4 A、CV = 0 B、CV = 1 C、CV < 4 D、CV >= 4A、0,0 B、3,0 C、1,1 D、3,1 A、0 B、1 C、先是1,再变为0 D、先是0,再变为1置位输出:常开触点M0.0闭合,Q0.0变为1状态并保存该状态,即使M0.0断开,Q0.0也保持1状态。 复位输出:常开触点M0.1闭合时,Q0.0变为0状态并保持该状态,即使M0.1断开,Q0.0也保持为0状态。 A、1 B、0 C、5 D、10RESET_BF指令需要两个参数,第一个是复位的位数

qq_52251819的博客 4421

Java 协变数组类型

问题   假设现在有 Person 类和 Employee 类,假设 Employee IS-A Person,那么,这是不是意味着数组 Employee[ ] IS-A Person[ ] 呢?换句话说,如果一个例程接受 Person[ ] 作为参数,我们能不能把 Employee[ ] 作为作为参数来传递呢? 思考   乍一看,似乎 Employee[ ] 就应该和 Person[ ] 类型兼容。举个例子,假设除了 Employee 外,还有 Student IS-A Person,并假设 Employ

Acx7的博客 686

Camera ITS测试

一、手机端设置: 将 CtsVerifier.apk 安装到设备上, 连接上linux主机。 二、主机端设置: 基础:CTS测试运行环境 然后,主机安装python2.7,及numpy/scipy/matplotlib/opencv 栈和 python 成像库。按照下面的命令依次安装: sudo apt­-get install python-­numpy sudo apt-­g...

wangubuntu的专栏 7786

浏览器工作原理与前端面试核心考点解析

浏览器作为Web应用的运行环境,其核心工作原理涉及渲染引擎、JavaScript执行机制和网络请求处理等多个关键技术点。渲染引擎通过解析HTML/CSS构建DOM树和CSSOM树,随后进行样式计算、布局和绘制,最终呈现页面内容。JavaScript执行则依赖事件循环机制,区分微任务和宏任务的优先级,同时需要关注内存管理以避免泄漏。网络请求处理涵盖从DNS解析到资源加载的完整流程,是性能优化的关键环节。这些底层原理不仅支撑着现代Web开发,也是前端工程师面试中的高频考点,特别是在处理跨域问题、浏览器存储方案对

weixin_33919950的博客 919

Dify DSL文件分享 Dify讨论群 大模型token资源等(持续收集更新)

基于LLMOps平台-Dify的一站式学习平台。包含不限于:Dify案例、DSL文件分享、模型接入、Dify交流讨论等各类资源分享。

同名公众号:dify实验室 3716

避开STM32H7的‘保护陷阱’:从Option Byte机制深度解析读写保护原理与预防

本文深度解析STM32H723VGT6的Option Byte保护机制,详细讲解RDP读保护和WRP写保护的工作原理及配置方法,并提供硬件设计防御策略和软件预防性编程技巧,帮助开发者避免误触发保护机制导致芯片锁定的问题。

weixin_33686714的博客 442

数组的协变

animals[0] = new Dog() { Id = 1, Name = "京巴" };animals[1] = new Dog() { Id = 2, Name = "土狗" };new Dog() { Id = 1, Name = "京巴1",Age=10 },new Dog() { Id = 2, Name = "土狗2",Age=20 }数组协变的概念:引用类型的数组,子类的数组类型可以赋值给父类的类型。// item是哪一种类型?// 虽然10是int类型,但值类型的数组没有协变。

weixin_74338405的博客 361

《大明王朝1566》中,朝廷财政危机无法解决的根源分析

财政困局中的财富最终流向三重黑洞:​皇室挥霍​(如嘉靖炼丹修殿)、特权阶层贪腐​(严党年入百万两盐税)、制度性损耗​(宗室供养、低效官僚)。更深层的“钱”其实是被禁锢在道德化治理的牢笼中——当国家用“黄河长江皆可为用”的权术思维替代制度性改革时,财政危机便成为帝制王朝无法逃脱的宿命。

为了小家奋斗 1973

[转]类型,转换,数组,协变及其他

为了让叙述简化,先定义几个用到的术语: 函数:可以给出输出的那种抽象体,变量可以认为是无参数函数。对于成员函数或者更习惯的叫做方法的那种函数,我认为它就是隐含了对象参数的函数。 类型系统是现在OO语言的核心和基石。类型系统是保证正确性的基础,现在的编程语言大多强调静态安全性,其实就是编译时类型正确性。动态类型系统对应着运行期类型检查,保证运行时的类型正确性。经常所说的安全性

Shopping的专栏 1215

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

C#进阶-协变与逆变

示例公式:若 A ≤ B,则 T。// 协变示例// 使用协变的接口// 隐式转换,获取 DerivedClass 实例。

2401_87252417的博客 1064

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

java 数组协变_java 数组协变

在某些情况下,即使某个对象不是数组的基类型,我们也可以把它赋值给数组元素。这种属性叫做协变(covariance)。在下面的情况下可以使用协变:数组是引用类型数组。在赋值的对象类型和数组基类型之间有隐式转换或显式转换。由于在派生类和基类之间总是有隐式转换的,因此总是可以将一个派生类的对象赋值给为基类声明的数组。只有数组存在协变,此功能有利也有弊,相对于List 是支持泛型 不支持协变class A...

weixin_39630999的博客 117

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C# 协变、逆变

微软官方概述: 在C#中,协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。协变保留分配兼容性,逆变则与之相反。 协变:能够使用与原始指定的派生类型相比,派生程度更大的类型。 逆变:能够使用派生程度更小的类型。 官方示例: string str = "test"; object obj = str; IEnumerable<string> strings = new List<string>(); IEnumerable<object> obj...

gman344的博客 233

关于Java的协变和逆变

逆变与协变:如果A、B表示类型,f(⋅)表示类型转换,≤表示继承关系(比如,A≤B表示A是由B派生出来的子类): f(⋅)是逆变(contravariant)的,当A≤B时有f(B)≤f(A)成立; f(⋅)是协变(covariant)的,当A≤B时有f(A)≤f(B)成立; f(⋅)是不变(invariant)的,当A≤B时上述两个式子均不成立,即f(A)与f(B)相互之间没有继承关系。 1.数组的协变性 在Java中数组是具有协变性的,如果B是A的子类型,则B[]是A[]的子类型(f(⋅)映射为数组

7K7K163的博客 251

深入解析C#数组协变与克隆机制

— 值类型与引用类型的内存行为差异。

钢铁男儿 493

C#进阶-协变与逆变(2)

C#中的逆变和协变是一组强大的泛型特性,它们为我们在处理泛型委托和泛型接口时提供了更灵活、更安全的类型转换机制。在面向对象的编程中,我们经常需要在不同层次的类之间进行转换,而逆变和协变正是为了在这些转换过程中提供便利。协变,即子类到父类的转换,使得我们能够以一种更通用的方式使用类型。这对于泛型委托和泛型接口的设计非常有用,允许我们在一些场景中将泛型参数类型更灵活地指定为其基类型。这种灵活性为代码的可扩展性和可维护性带来了巨大的优势。

2401_87252357的博客 890

C#进阶-协变与逆变(1)

C#中的逆变和协变是一组强大的泛型特性,它们为我们在处理泛型委托和泛型接口时提供了更灵活、更安全的类型转换机制。在面向对象的编程中,我们经常需要在不同层次的类之间进行转换,而逆变和协变正是为了在这些转换过程中提供便利。协变,即子类到父类的转换,使得我们能够以一种更通用的方式使用类型。这对于泛型委托和泛型接口的设计非常有用,允许我们在一些场景中将泛型参数类型更灵活地指定为其基类型。这种灵活性为代码的可扩展性和可维护性带来了巨大的优势。与协变相反,逆变提供了一种父类到子类的转换方式。

2401_87252283的博客 701

深入理解 c# 第二章 数组协变以及执行时类型检查

class ArrayVariance { static void Main() { string[] strings = new string[5]; object[] objects = strings; objects[0] = new object(); ...

eyetired的博客 621

C#2.0新增功能06 协变和逆变

系列目录【已更新最新开发文章,点击查看详细】 在 C# 中,协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。 协变保留分配兼容性,逆变则与之相反。 以下代码演示分配兼容性、协变和逆变之间的差异。 // 分配兼容性. string str = "test"; // 将派生类型更高的对象分配给派生类型更低的对象 object obj =...

weixin_30501857的博客 73

JAVA中的协变与逆变

JAVA中的协变与逆变 首先说一下关于Java中协变,逆变与不变的概念 比较官方的说法是逆变与协变描述的是类型转换后的继承关系。 定义A,B两个类型,A是由B派生出来的子类(A<=B),f()表示类型转换如new List(); 协变: 当A<=B时,f(A)<=f(B)成立 逆变: 当A<=B时,f(B)<=f(A)成立 不变: 当A<=B时,上面两个式子都不...

weixin_30664051的博客 112
上一篇: C/C++之冲突和共处
下一篇: 基本概念辨析
lifeNet
博客等级 码龄20年 1粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值