C#与C++多态性对比分析1

Windows下通过Ollama安装使用DeepSeek本地大模型 本地安装运行Deepseek大模型 阅读详情

 

1.1 什么是多态性

 在面向对象的系统中,多态性是一个非常重要的概念,它允许客户对一个对象进行操作,由对象来完成一系列的动作,具体实现哪个动作,如何实现由系统负责解释。

多态性的定义是:同一操作作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的执行结果。C#C++均支持两种类型的多态性:编译时多态性和运行时多态性。前者是在编译的过程中确定了同名操作的具体操作对象,而后者则是程序运行过程中动态地确定操作所针对的具体对象。这种确定具体对象的过程就是联编。联编是指计算机程序自身彼此关联的过程,也就是把一个标识符名和一个存储地址联系在一起的过程:用面向对象的术语讲,就是把一条消息和一个对象的方法相结合的过程。按照联编进行的阶段的不同,可以分为两种不同的联编方法:静态联编和动态联编,这两种联编过程分别对应着多态的两种实现方式。

u     静态联编
   
联编工作在编译连接阶段完成的情况称为静态联编。因为联编过程是程序开始执行之前进行的,因此有时也称为早期联编或前联编。在编译,连接过程中,系统就可以根据类型匹配等特征确定程序中操作调研能够与执行该操作的代码的关系,即确定了某一个同名标识到底是调用哪一段程序代码。有些多态类型,其同名操作的具体对象能够在编译、连接阶段确定、通过静态联编解决,比如重载。

u     动态联编
   
和静态联编相对应,联编工作在程序运行阶段完成的情况称为动态联编,也称为晚期联编或者后联编。在编译、连接过程中无法解决的联编问题,要等到程序开始运行之后再来确定,包含多态中操作对象的确定就是通过动态联编来完成的。

交通工具是多态性的一个很好的例子。一个交通工具接口可以只包括所有交通工具都具有的属性和方法,还可能包括颜色、车门数、变速器和点火器等。这些属性可以用于所有类型的交通工具,包括轿车、卡车和客车。

面向对象的多态性还可以分为三类:重载多态、强制多态、包含多态。普通函数以及类的成员函数的重载都属于重载多态;运算符重载,比如加法运算分别使用于浮点数、整数之间就是重载的实例。强制多态是指将一个变元的类型加以变化,以符合一个函数或者操作的要求,前面所讲的加法运算符在进行浮点数与整数相加时,首先进行类型强制转换,把整型数变为浮点数再相加的情况,就是强制多态的实例。包含多态是研究类族中定义于不同类中的同名成员函数的多态行为,主要是通过虚函数来实现。下面我将从这四个方面来对比C++C#的多态性。

1.2 C++C#中重载多态性分析

1.2.1 C++函数重载解析

假如我们有一组数学函数,它们的原型如下所示。所有函数都完成相同的任务,但是它们所接受的参数类型不同:

int foo( int x, int y);

double foo(double x, int y);

int foo(int x,double y);

现在我们假设主程序中调用下面这个函数:

double u;  double v;

double w = foo(u,v);

我们很难判定它究竟会选择哪个函数调用。因为其实出现了两个适合的函数原型,即foo(double x, int y)foo(int x, double y)。所以以上情况发生时,编译器就会报错。

C++C#编译器都有自己的一些算法用于重新解析。为了进行重新解析,函数以它的签名来表示,签名就是函数名加上它的参数列表(参数的数量以及每个参数的类型)。值得注意的是,函数的返回类型以及函数所抛出的异常的类型不包括在函数的签名以内,因此它们不会在重载解析中发挥任何作用。以下是各种不同层次的特异性,根据它们,在C++中的一个函数调用的实参可以与函数定义中的对应形参进行匹配。

特异性层次1 当我们把一个实参与其对应的形参进行匹配时,如果两者的类型完全相同或者只需要进行微小的转换,那么我们就能得到具有佳特异性的匹配。这种微小的类型转换的例子包括数组名转换为指针、函数名转换为函数指针以及类型T转换为const T 等。

特异性层次2 如果实参类型和形参类型之间的转换需要进行类型升级,我们所得到的匹配比以前那种匹配的特异性要差一点。所谓的类型升级是指:(1)整形转换为整形;(2)非整形转换为非整形;(3)并且转换不会产生信息损失。

特异性层次3 匹配特异性较前一种匹配更低一级的是涉及标准转换的匹配。基本类型的标准转换的例子包括intdouble,doubleint型等(C#,double int 是不允许的)。对于指针类型,标准转换包括T*void *int* unsigned int*等。对于类类型而言,从派生类转换为基类都是标准转换。最后一种类型的转换使我们可以把一个指向派生类对象的指针转换为一个指向基类的指针。

特异性层次4   这是一种更低级别的特异性层次,需要一个用户定义的类型转换才能进行的匹配。

特异性层次 5  通过在函数定义中使用的省略号所得到的匹配是特异性最差的匹配。

我们来看下面这个例子:

#include<iostream>

using namespace std;

void foo(int i,long j)

{

      cout<<"The first foo was called ! ";

}

void foo(long i,int j)

{

      cout<<"The second foo was called ! ";

}

void main()

{

      long x=10,y=10;

      foo(x,y);

}

我们可以看到由于foo(x,y)函数调用的实参类型与第一个和第二个foo函数定义的形参类型匹配。应该选择哪一个呢?我们又进行进一步比较发现第一个和第二个foo函数都符合特异性层次3,所以编译器无法确定应该调用哪个函数,将会报以下错误:

error C2666: 'foo' : 2 overloads have similar conversions

分析可以知道重载解析将选择能够提供最佳匹配的特异性的函数。如果超过一个的函数能够达到最高层次的匹配特异性,那么就会出现歧异,导致一个编译错误。

综上所述,只有函数的签名允许参与重载解析算法。由于返回类型和函数所抛出的异常的类型并不包括在函数的签名中,因此它们对重载解析不会有任何影响。重载解析也与函数的声明顺序无关。此外,在不同的作用域中声明的函数不属于重载的范畴。

1.2.2 C#方法重载解析

C++一样,C#的重载解析也是根据匹配特异性概念进行的,如果存在超过一个的方法,它们的形参与一个方法调用的实参相匹配,编译器将从中选择一个匹配特异性最高的方法。如果超过一个的方法具有同等层次的匹配特异性,那么编译器就会认为产生了歧义,它将发出一条编译时错误信息。C#的重载解析是以下这几个步骤。

(1)    如果给定了适用的候选函数成员集,则在其中选出最佳函数成员。

(2)    如果该集合只包含一个函数成员,则该函数成员为最佳函数成员。

(3)    否则,最佳函数成员的选择依据是:各成员对给定的参数列表的匹配程度。比所有其他函数成员匹配得更好的那个函数成员就是最佳函数成员。且使用以下规则进行比较:
   
给定一个带有参数类型集 {A1, A2, ..., AN} 的参数列表 A 和带有参数类型 {P1, P2, ..., PN} {Q1, Q2, ..., QN} 的两个可应用的函数成员 MP MQ,则在以下情况中,MP 定义为比 MQ 更好的函数成员: 对于每个参数,从 AX PX 的隐式转换都不比从 AX QX 的隐式转换差,并且对于至少一个参数,从 AX PX 的转换比从 AX QX 的转换更好。

(4)    如果不是正好有一个函数成员比所有其他函数成员都好,则函数成员调用不明确并发生编译时错误。

虽然C#的函数重载解析所采用的方法和C++方法大体上是一样的,但算法的细节还是有些不同,其具体情况如下:

(1)    C++所允许的许多类型转换在C#中是不允许的。事实上,在函数调用中,C#只允许从派生类转换为超类或者超接口类(扩大转换),但不允许收缩转换(从double 转换为int32,int16),如果一定要使用这种转换,那么必须显示的使用强制转换符来表明。

(2)    C#中不允许在C++中可以使用的用户定义的类型转换。

(3)    C#中不存在省略号,所以这一特性层在C#中没有。

     我们可以看下面这个例子:

 #include<iostream>

using namespace std;

void foo(int i,int j)

{

      cout<<"The foo was called ! "

<<endl;

}

void main()

{

      long x=10,y=10;

      foo(x,y);

}

程序运行输出是:

The foo was called !

可以看到在C++中是允许把long转换为int 类型进行函数调用的。但是在C#中是不允许把double转换为int类型的。即C#中不允许进行收缩转换,因为有可能会使内存产生溢出。如果非要转换的话,就必须使用类型强制转换符。

1.2.3 C++运算符重载

运算符重载是对已经有的运算符赋予多重含义,使同一个运算符作用于不同的类型的数据导致不同类型的行为。运算符重载实质就是函数重载。在实现过程中,首先把指定的运算表达式转换为对运算符函数的调用,运算对象转化为运算符函数的实参,然后根据实参的类型来确定需要调用的函数,这个过程是在编译过程中完成的。

C++的运算符重载的规则如下:

(1)    C++中运算符除了类属关系运算符“.”、成员指针运算符“*”、作用域分辨符号“::”、sizeof运算符和三目运算符“?”不能被重载,其他的都可以重载,但只能重载C++中已有的运算符。

(2)    重载之后运算符的优先级和结合性都不会改变。

(3)    运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造。一般来讲,重载的功能应当与原有的功能相类似,不能改变原运算符的操作对象个数,同时至少要有一个操作对象是自定义类型。

1.2.4 C#运算符重载

C#中的操作符重载的作用与C++是一致的,但是C#中的操作符重载也有其自己的特点。如下所示:

(1)    C#中,操作符重载总是在类中进行声明,并且通过调用类的成员方法来实现。操作符重载声明的格式为:type operator operator-name(formal-param-list)

(2)    C#中不能被重载的操作符:=&&||?:、newtypeofsizeofis其他的都可以重载,但只能重载C#中已有的运算符。

(3)    C#中的操作符重载与C++唯一一点不同在于C#中的运算符重载函数必须是静态的。

1.3 C++C#中强制多态性分析

数据类型的转换就是,将存储在变量中的数值由一种类型转换成另外一种类型。在C++中,数据类型转换可以是隐式的,也可以是显式的:

      float I = 100.1;

      long j = I;      //隐式转换

      int k = (int)I;   //显式转换

      int m=int(I);   //显式转换,新C++风格

显式的数据类型转换,就是在代码中显式的指出目标数据类型。C++中,有两种显式的数据类型转换格式——旧的C风格,其中数据类型名放在括号内。新风格,其中变量名放在括号内。C++允许在所有基本数据类型之间进行转换。如果目标数据类型的范围比源数据类型的范围小,就会有丢失数据的危险。这时,编译器会根据警告级别的设定来提出警告。在上例中,隐式的数据类型转换可能会导致数据丢失,编译器会提出警告。当进行显式的数据类型转换时,编译器会认为你清楚您所做的事情,所以一般不提出警告。

C#的类型安全性要比C++要高,所以它的数据间的转换不灵活。C#的显式转换和隐式转换都是正式的转换。定义为隐式的转换可以用显式或隐式两种转换来执行。而对定义为显式转换的数据转换使用隐式转换会出现错误。这点与C++不同,C++只会出现警告。

C#中,关于数值类型与其他类型之间的转换规则,是很有逻辑性的。隐式转换不会导致数据丢失——如intlongfloatdouble。显式转换可能会导致数据丢失,引发溢出错误、符号错误或者部分数据损失。比如,floatintintuint或者shortunlong。另外,由于Char与整型是相区别的,所以在与Char的转换中,只能使用显式转换。

下面的代码在C#中是有效的:

float f1 = 420.0F;

long l1 = (long)f1;

short s1 = (short)l1;

int i1 = s1;

uint i2 = (uint)i1;

C#中,显式转换数据类型总是用旧的C风格语法,不能用C++新的风格:

uint i2 = uint(i1);

 C#中,可以在检查环境中执行数据类型转换和其他的数学运算。这意味着.NET运行环境会检测是否发生了溢出。若发生了溢出,则会抛出一个异常(尤其是一个OverFlowException)。C++中不存在这一特性。

Checked

{

   int I1= -3;

   uint I2 =(uint)I1;

}

因为在checked 环境中,第二行代码将会抛出一个异常。如果不指定checked,就不会抛出异常,I2变量中将包含无用信息。

 

29、编程中的类型统一多态性深度解析 本文深入解析了编程中的类型统一多态性,探讨了它们在不同编程语言中的实现和应用。文章详细分析了类型等价、类型兼容、结构等价名称等价的区别,以及泛型在C++、Java和C#中的设计特点权衡。通过对比不同语言的泛型实现方式,帮助开发者理解类型系统的重要性,并根据项目需求选择合适的编程语言和方法。 阅读详情

相关推荐

【温室气体数据集】全球总碳柱观测网络 TCCON

【温室气体数据集】全球总碳柱观测网络 TCCON

WW、forever的博客 391

C#编程语言的优势C++对比

本文介绍了C#的来源、优势主要功能,同时介绍C#C++的主要区别

qiaodahua的博客 4085

Java、C#C++在继承、覆盖、多态及抽象类中的特性对比分析

在现代软件工程中,面向对象编程(OOP)已成为主流的程序设计范式。其四大基本特征——封装、继承、多态抽象,构成了构建可维护、可扩展系统的基础。要素语法符号是否必需作用继承关键字extends是声明类继承关系访问控制publicprotected/ 默认 /private否(默认包内可见)控制成员可访问范围方法重写@Override否(推荐使用)提供编译时校验,增代码健壮性构造器链调用super(...)

weixin_29885875的博客 1084

C++多态性C#的比较

多态性:统一操作作用于不同的对象可以有不同的解释,产生不同的执行结果。多态性可以分为两种:一是编译时的多态性,一是运行时的多态性。 编译时的多态性包括重载、覆盖、运算符重载。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。 运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C++中运行时的多态性使用虚函数和纯虚函数(...

weixin_30709061的博客 306

c#C++的区别总结

C#是三大主流OOP(面向对象编程)语言(C++,Java,C#)之一,也是最新的一种,其中必然借鉴了前两者的长处,“否则它的缔造者就该打屁股”——候捷语,见《C#Primer中文版》的译续:-)它们三者有太多的共性,其语法和编程概念,绝大部分彼此兼容,精一而通三。尤其对熟练掌握C++的程序员而言,学习Java和C#没有任何难度,唯一需要花些时间的地方就是熟悉这二者的类库。三者中,C++是我最熟悉也

hyqsong的专栏 5508

C#C++的一些语法区别

这学期有C#的课,由于之前有C和C++的一些基础,所以并没有从头开始学习其语法,在这里总结一下实际使用中发现的C#C++的一些区别,便于以后使用时进行查阅(其实是为了考期复习方便2333) C、C++C#在宏观上的区别 C是完全面向过程的语言,用于开发规模较小的程序效率很高,但是程序较大,就显得代码量多,编写效率下降了。 C++是半面相对象的,引入了类的封装性、继承性、多态性大大简化...

angus_monroe的博客 8971

C++C#中包含多态性分析

 C#中包含多态性分析包含多态性是指通过继承提供多态性。包含多态性反映了能够在多于一个类的对象中完成同一事物的能力——用同一种方法在不同的类中处理不同的对象。例如,Customer和Vendor对象都有一个Name属性,则我们可以写一个事物来调用Name属性而不管我们所使用的是Customer对象还是Vendor对象,这就是包含多态性。包含多态性是运行时多态。      

hardwayboy的专栏 928

C语言、C++C# 三者的区别

按时间顺序说一说这三门语言的基本吧,这样比较一下儿就能知道他们的区别了。 一:C语言 C语言诞生得非常早,当时人们普遍还习惯用汇编语言编写软件,而且没有什么统一,通用的操作系统,基本上软件都是从0开始写的。C语言的目标就是比汇编方便易用,同时不要损失汇编的表达能力。所以C语言可以看成是“高级的汇编”语言。C语言的源代码基本上可以非常容易地对应到汇编代码,而且可以不需要什么运行时环境的支持。C的...

qq_34573534的博客 1万+

对于多态性的学习总结---虚函数的有没有

                                  对于多态性的学习总结 我不想在这里讲整个关于C++中的多态性机制,那些资料你可以在网上搜索到一大堆。我想着重讲一下我对于多态性中的动态多态性的一些研究总结。还是得先大致地说说多态性这个东西。所谓多态性,简单地说就是一个名称,但是具有多种语义。多态性的发明有什么意义呢?考虑一下,假如现在你要实现一个打印不同信息的功能

loop in codes 1877

C#中继承的多态性

有很久没写博客了,最近学C#。哎~说来惭愧,各种语言都学得不精啊,学了C++,学到了一半,现在又转头学其他的。主要是大学课程的安排很不合理(至少我是这么认为的)。没门都没学精,老师讲得都是很基础的,要学精还是要靠自己,而C++完全是自学的。。。 好吧,不多说了,多态的意思是一种事物有多种形态,其实为什么写这个,主要是我想和java进行区别,之前学习java语言,在继承的多态上也花了不少时间,而C

IT之路 558

C#JAVA的相同不同之处

文章目录C#JAVA的相同之处C#JAVA的不同之处1、属性2、index3、delegate4、event5、enum:枚举用于指定一系列的对象。6、foreach语句7、统一数据类型:8、操作符重载9、多态性 C#JAVA的相同之处 由于C#JAVA都是基于C++发展起来的,因此二者之间具有很多相似之处,具体如下: 1C#和JAVA语言的编译结果是独立于计算机和编程语言的,可执行文件可以在受管理的执行 环境中执行; 2、C#和JAVA语言都是采用了自动的垃圾回收机制; 3、C#和JAVA语言都

weixin_40162095的博客 2733

c++ C#比较

对于新手来讲 vc比c#难很多(入门学习) 实现同样的功能,vc的代码量要比c#多很多 对于高手来讲 他要考虑是项目的需求 是要程序运行速度快的那种,还是开发速度快的那种   C#不需要用到麻烦的mfc类,不需要头疼的*.h……  C#基于FrameWork,你可以调用FrameWork封装的类,当然也可以用api.  不过C#的执行通过了虚拟机,执行起来比VC要慢:

照玄 4665

Object PascalC++面向对象特征的对比

<br />Object PascalC++面向对象特征的对比<br />Comparisons of Object-Oriented Features between Object Pascal and C++<br />两江<br />liangjiang@jxmail.com.cn<br />?<br />摘要:论述了Object Pascal和C++两种程序设计语言中各自的面向对象特征,并作了一定的对比。<br />Abstract:The features of the two Object

chla的专栏 1460

VC Formal -- Introduction

Formal verification is complimentary to simulation-based verification,provides exhaustive analysis to ensure signoff quality verification

H_H_h_h99的博客 1416

编程语言串烧(一)

编程语言串烧(一) C++ vs. C# 如果将C++C#这样的面向对象编程语言来做对比 C++着重调的是类型的自主管理,通过定义方法来保证形式上的简单统一化,比如内存的自主管理,再比如将自定义类型和内部数据类型比较。 而C#调的是内部方法的交互作用以实现对象的引用操作,如 Object.ToString 方法就可以用来给外部展现内部的数据。从这个角度来说C++代码编写的

dashing_man的专栏 871

虚函数效率真的低吗?看起来只是多了一次函数调用,为什么都说它效率低呢?| 虚函数 | C++

在程序设计的世界里,有些概念看似简单,却常被误解。虚函数在面向对象编程中作为实现多态性的核心机制,常为初学者所推崇;然而在资深工程师眼中,其所引入的运行时开销潜在的性能影响,亦常成为讨论权衡的焦点。

1247

C#C++

Ø  输入输出的不同 C++的输入时cin,输出为cout,而C#的控制台输入和输出(I/O)是Console.Read()/Console.ReadLine和Console.WriteLine()/Console.Write。 u  Console.Read()/Console.ReadLine Console.Read: Concole.Read()用于获取输入值的ASCII值,返回值是

李晓娜 1454

C# 语法 vs. C++ 语法:全面对比核心区别解析

C#C++ 在语法和特性上存在显著差异,选择哪种语言取决于你的项目需求和技术背景。C# 更适合快速开发和现代化应用,而 C++ 则更适合高性能和系统级开发。无论选择哪种语言,掌握其核心特性和语法都将为你的职业发展带来巨大的帮助。

不会编程的码农研究僧 2449

C# 多态性

多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。 多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。 静态多态性 在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。C# 提供了两种技术来实现静态多态性。分别为: 函数重载 运算符重载 运算符重载将在...

weixin_34319640的博客 256

C++ 什么是多态多态的用途

 联系人:石虎 QQ:1224614774  昵称: 嗡嘛呢叭咪哄                       QQ群:807236138  群称: iOS 技术交流学习群 一、概念 1. 定义:“一个接口,多种方法”,程序在运行时才决定调用的函数。 2. 实现C++多态性主要是通过虚函数实现的,虚函数允许子类重写override(注意和overload的区别,overload是重...

石虎 8737

缠论指标公式,适用于TB量化软件

指标仅适用于TBQuant量化软件,导出时的版本为:V1.4.0.7,低于此版本不能导入。

上一篇: C#与C++类的继承机制的对比分析(3) (钟豪原创)
下一篇: C++与C#中包含多态性分析
hardwayboy
博客等级 码龄19年 5粉丝 9原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值