虽然这个话题看着似乎有些关公战秦琼的味道,但是作为游戏开发者,C++和C#一定是绕不开的两门语言。不过虽然说是比较二者差异,因为我学习的过程主要是先学C++,所以我先基于C++的认知,再来聊聊C#之中的不同。

(为什么会想到写这个帖子是因为我发现老是记混二者名字相同但是底层完全不同的概念,只能说很烦)

讨论差异之前,我们先来聊聊大体上二者的相似之处。

二者都是编译执行的强类型语言,都是基于OOP思想,都支持泛型。

我们首先来聊第一个不同的点——C++的指针。

指针

C++中的指针是一个用来存储变量地址的变量,其底层涉及到了内存管理的内容,众所周知指针给C++带来了高性能的同时也带了很多麻烦,指针本身的管理就是一个麻烦,比如什么野指针,悬空指针,空指针,指针与指针之间又可以传递,还有一系列诸如常量指针和指针常量的内容。

C#中并非不可以使用指针,C#中有内存分层的概念:

针对原生内存我们就需要像C++一样通过指针去访问和管理,但是不讨论这种特殊情况的话,在C#的代码中我们是看不到指针的,那这时候我们还是需要一个存储变量地址的变量呀,不然怎么进行内存的访问呢?这个就是我们C#的引用类型。

这里我先说一下C#的数据类型分类,大体上分成值类型和引用类型。

这里补充一下关于System.Object和System.ValueType的内容:

Object类是C#中所有对象的基类。

通过上述的介绍,相比你也知道了,引用类型就是一个类型安全的托管指针,用来存储堆中对象的地址,我们修改引用类型的值就会直接修改实际的数据,我们拷贝值类型时会拷贝出一个副本而拷贝引用类型会拷贝实际的数据。

这里又涉及到一个问题,我们知道修改C++的指针时,我们既可以修改指针指向的地址也可以通过指针修改地址存储的值,那我们修改对应的C#的引用类型的变量时,如何具体判断修改的是地址还是地址存储的值呢?

先说结论的话,C#的引用是无法修改存储的地址的值的,所以我们不用区分,因为一般情况下我们只能修改引用类型的值。

难道我们就没有办法去修改引用指向的地址吗?

ref关键字可以帮助我们实现引用的地址修改。

 

C# 引用类型实现了 C++ 指针的核心权能——提供对堆内存对象的间接访问与修改能力,并支持高效的数据共享,移除了指针算术、任意重定向等危险操作,通过 GC 自动管理生命周期,体现了 C# ​​“安全优先”的设计理念。 

抽象类&&接口

C++如何实现抽象类?很简单,用一个纯虚函数来做就好了。

class A {
public:               // ✅ 必须 public 才能被覆盖virtual void a() = 0; // ✅ 虚函数需 virtual
};

但是当你来到C#中,你发现好像没有纯虚函数这种写法,取而代之的是abstract关键字:

public abstract class A { // ✅ 类必须标记 abstractpublic abstract void a(); // ✅ 无方法体,无{},直接分号结束
}

这个概念同样地影响到了接口interface的实现:

// C++ 通过纯抽象类模拟接口(无成员变量,无实现方法)
class IShape {
public:virtual ~IShape() = default;        // 虚析构(必须)virtual double GetArea() const = 0; // 纯虚方法(接口函数)virtual void Draw() const = 0;       // 纯虚方法(接口函数)
};

这是C++的接口实现,所有接口内的方法都必须是纯虚函数。

// C# 原生接口(无成员变量,无构造逻辑)
public interface IShape {double GetArea();    // 接口方法(自动public)void Draw();         // 接口方法(自动public)
}

C#中已经专门集成了接口的概念,用关键字interface即可。

总结来说的话,C的抽象类是通过我们的一个纯虚函数来实现的,某一个类之中如果有一个纯虚函数我们就把这个类认作这个抽象类。然后C++的接口就是类中的所有函数都是纯虚函数我们就把这个类看做一个接口,继承这个接口的方法就必须要提供这些方法的全部实现。然后C#的话关于抽象类它有一个专门的关键字叫abstract,我们用这个关键字修饰类那么这个类就是一个抽象类,要求其中的这个类中的至少有一个方法也是被abstract修饰的抽象方法,而我们的那个接口的话也是有原生集成的一个interface关键字,我们用interface关键字来修饰类那么这个类就会被视作一个接口我们只需要在这个类中来呃提供方法的声明就可以。

只读

在C++中,实现只读的关键字有constexpr和const。

对于C++来说,这两个关键字最大的差异就是具体何时赋予变量只读的属性,对应的,什么时候赋予只读的属性就要求什么时候进行初始化。而在C#中也有两个关键字实现只读,但是这两个关键字变成了const和read only。

可以看到同样叫const,在C++中是运行时常量结果到了C#变成了编译常量。

String

C#的string作为一个引用类型,我们在讨论值类型和引用类型的区别时有提到,修改值类型往往都是修改其副本而修改引用类型往往都是直接修改其值,那么string作为引用类型,一定也是这样的吧?

如果真是这样我就不会在这里把这个点列举出来了,实时上C#中的string非常特殊:具有不可变性

如何理解不可变性?当我们写这样一段代码:

string a="abc";
a+='c';

首先a本身就是一个string的对象,一开始的时候是一个没有内容(但是有内存)的空字符串"",然后"abc"本身也是一个字符串,我们把"abc"丢给a,然后我们后续要对a添加字符'c'时,c本身也是一个字符(串?双引号就是字符串单引号就是字符),由于C#中string的不可变性,我们的堆中会重新生成一个a的副本,然后把'c'丢给a的副本,然后返回a的副本,a本身就作为堆上的垃圾等待回收了。

一言以蔽之,C#将string赋予了不可变性,这是有理由的:

可以看到赋予string不可变性后,线程安全的问题就从根源上被解决了。

迭代器

C++中的迭代器是STL库中帮助我们访问容器内部具体元素的一个封装了指针的工具,但是C#中可没有STL库,更没有指针用来封装,那么C#的迭代器是干嘛的呢?

聊到这个,我需要先来说一下C#的foreach和for这两种数据遍历方式。

foreach是只读循环,不可以修改遍历的元素,不用获取数组的长度,以及由额外的GC开销。前两者非常好理解,但是第三点额外的GC开销是从何而来的呢?

这里其实也可以看到C#底层的数据集合实现,很多都是基于IEnumerable接口实现的,这样我们调用foreach进行遍历时直接调用接口的方法获取一个迭代器来遍历元素。然后这里还牵扯到一个状态机类:

当我们使用yield return方法时,编译器就会帮助我们实现一个状态机类实时记录方法执行到哪一步,这个状态机对象本身在堆上,所有会有GC开销。 

Using 

这里算是一个补充,C++和C#中的using都有着引用命名空间以及修改命名空间命名的作用,但是C#中还多了一个功能就是可以帮助我们释放实现了IDisposable接口的资源。

委托/回调

C++中并没有委托这个概念,但是有基本的回调函数的概念,具体来说就是允许在函数的参数列表中放入函数的指针,然后在函数体中直接利用这个指针来调用函数体以外的函数。

  void callback(int x) { /* ... */ }void doSomething(void (*func)(int)) {func(42); // 回调}

C#中的委托其实本质上也是一样的思想:不过delegate是一种类型安全的函数指针。

  public delegate void MyCallback(int x);void DoSomething(MyCallback cb) {cb(42); // 回调}

在这个delegate的基础之上,C#还实现了event,action和function。

C# 中的 delegate 是类型安全的函数指针,是回调和事件机制的基础;event 是对委托的事件化封装,实现发布-订阅模式,限制了外部访问;Action 和 Func 是 .NET 内置的泛型委托,分别用于无返回值和有返回值的场景,极大简化了委托的声明和使用。四者本质上都是委托机制的不同表现形式,适用于不同的开发需求。

结构体

有一个最基本的差异:C++的结构体支持继承而C#的不支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/92285.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92285.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/92285.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rocky9-zabbix简单部署

目录 一、准备 1、(rocky9) 2、配置数据库 二、配置文件 1、导入初始架构与数据 2、配置相关文件 三、启动服务 1、浏览器访问 2、解决乱码问题 ​编辑 四、监控 ① 添加主机 1、修改配置文件 2、启动服务 3、网页添加 ②添加监控模块 1…

tabBar设置底部菜单选项、iconfont图标(图片)库、模拟京东app的底部导航栏

欢迎来到我的UniApp技术专栏!🎉 在这里,我将与大家分享关于UniApp开发的实用技巧、最佳实践和项目经验。 专栏特色: 📱 跨平台开发一站式解决方案 🚀 从入门到精通的完整学习路径 💡 实战项目经…

7.22总结mstp,vrrp

一、MSTP技术MSTI和MSTI域根MSTP中的端口角色3. MSTP工作原理 MSTP 计算方法• CST/IST的计算和RSTP类似 • MSTI的计算仅限于区域内 • MSTI计算参数包含在IST BPDU中,和IST的计 算同步完成&#xfe…

【电脑】网卡的基础知识

网卡(Network Interface Card, NIC)是计算机中用于连接网络的关键组件之一,它负责管理和发送数据包到互联网或其他局域网设备。下面是一些关于网卡的详细知识:网卡的基本结构MAC地址:每个网卡都有一个唯一的物理地址&a…

IPv4枯竭时代:从NAT技术到IPv6的演进之路

🔍 开发者资源导航 🔍🏷️ 博客主页: 个人主页📚 专栏订阅: JavaEE全栈专栏 IPv4(Internet Protocol version 4)是互联网最核心的通信协议之一,自 1981 年正式标准化以来…

模式结构-微服务架构设计模式

需求(Forces)结果上下文(Resulting context)相关模式(Related patterns)需求:必须解决的问题需求部分描述了必须解决的问题和围绕这个问题的特定上下文环境。需求有时候是相互冲突的,所以不能指望把他们全部都解决(必须取舍&#…

30个常用的Linux命令汇总和实战场景示例

下面汇总常用的 30 个常用的 Linux 命令,每个都附有简要说明和典型示例,适合日常开发、服务器维护或系统学习使用。30 个常用的 Linux 命令汇总 一、文件与目录操作(基础)命令说明示例ls列出文件和目录ls -l 显示详细信息cd切换目…

Taro 网络 API 详解与实用案例

Taro 网络 API 详解与实用案例 在现代前端开发中,网络通信是不可或缺的一环。Taro 作为一款多端开发框架,提供了丰富且统一的网络 API,帮助开发者在小程序、H5、React Native 等多端环境下高效地进行数据交互。本文将详细介绍 Taro 的四大网…

Bitbucket平台的HTTP Access Tokens操作手册

在Bitbucket平台添加HTTP Access Tokens(用于替代密码进行认证)。 1. 登录Bitbucket并访问个人设置 打开 Bitbucket 并登录账号。点击右上角头像 → 选择 Manage account。 2. 生成Access Token 在左侧菜单中选择 Access tokens(位于 Sec…

低成本、高泛化能力的无人机自主飞行!VLM-Nav:基于单目视觉与视觉语言模型的无地图无人机导航

作者:Gobinda Chandra Sarker1^{1}1, AKM Azad2^{2}2, Sejuti Rahman1^{1}1, Md Mehedi Hasan1^{1}1单位:1^{1}1达卡大学,2^{2}2伊玛目穆罕默德伊本沙特伊斯兰大学论文标题:VLM-Nav: Mapless UAV-Navigation Using Monocular Visi…

Docker Desktop 安装到D盘(包括wsl)

默认WSL虚拟机位置&#xff1a; C:\Users\<用户名>\AppData\Local\Docker\wsl重装DockerDesktop下载安装包Docker Desktop Installer.exe在D盘创建文件夹D:\Program Files\DockerDesktopD:\Program Files\DockerDesktop\data 在cmd运行 start /w "" "Dock…

网络协议(三)网络层 IPv4、CIDR(使用子网掩码进行网络划分)、NAT在私网划分中的应用

利用子网掩码进行子网划分 这是一个模拟搭建的私网&#xff0c;有俩台主机ab。现在主机a要给云端服务器发送一条消息&#xff0c;这条消息怎么才能到达云端服务器呢&#xff1f;确定这条数据中的源端为本地ip的9000端口&#xff0c;目的端为24.24.24.8888端口&#xff0c;首先&…

8.4 Java 原生 TCP Socket 实现 HTTP 请求解析和请求分发

使用 Java 原生 TCP Socket 实现 HTTP 请求解析和请求分发&#xff0c;是一个理解 HTTP 协议底层原理的好方法。虽然 Java 提供了 HttpServer 类来简化 HTTP 服务器开发&#xff0c;但如果你想从 TCP 层 开始构建一个简单的 HTTP 服务器&#xff0c;可以使用 ServerSocket 和 S…

自研能管项目开发界面

自研能管软件实现一个界面开发 目的&#xff1a; ​ 通过接口方式实现展示哪些数据例如&#xff1a; ​ 已知制丝车间下的计量电表&#xff0c;在可视化界面通过点击制丝车间的方式&#xff0c;自动在MySQL存储制丝车间的电表数据(假设是每分钟存储一次)&#xff0c;前端即可以…

【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 基于wordcloud库实现词云图

大家好&#xff0c;我是java1234_小锋老师&#xff0c;最近写了一套【NLP舆情分析】基于python微博舆情分析可视化系统(flaskpandasecharts)视频教程&#xff0c;持续更新中&#xff0c;计划月底更新完&#xff0c;感谢支持。今天讲解基于wordcloud库实现词云图 视频在线地址&…

Vue3 面试题及详细答案120道(31-45 )

《前后端面试题》专栏集合了前后端各个知识模块的面试题&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

Proxmox VE 8.3/8.4开启Intel 核显的vGPU,搭建vGPU云桌面系统

1. Intel Graphics SR-IOV 介绍Intel Graphics SR-IOV 是 Intel 最新的图形虚拟化技术。单根 I/O 虚拟化 &#xff08;SR-IOV&#xff09; 通过将设备划分为多个虚拟功能来定义共享物理设备功能的标准方法。每个虚拟函数都直接分配给一个虚拟机&#xff0c;从而为虚拟机实现接近…

LeetCode 热题100

文章目录哈希两数之和字母异位词分组最长连续序列双指针移动零盛最多水的容器滑动窗口子串多刷题 LeetCode 热题100 哈希 两数之和 思路分析&#xff1a; 暴力做法&#xff1a;每一个数字都与剩余的数字作比较&#xff0c;时间复杂度是O(n2)O(n^2)O(n2)哈希做法&#xff1a;我…

Idea或Pycharm上.idea的忽略提交的问题总结

文章目录问题描述如果是首次提交或者之后的提交代码时把.idea及其文件提交到远端仓库中&#xff0c;此时再创建.gitignore会不生效。问题描述 由于在代码托管平台上创建的项目&#xff0c;没有关联创建.gitignore文件。导致git 克隆到本地电脑上时&#xff0c;项目的根目录下也…

【锁】MySQL中有哪几种锁?

&#x1f4da; 欢迎来到我的Java八股文专栏&#xff01; &#x1f389; 各位程序员小伙伴们好呀~ &#x1f44b; 我是雪碧聊技术&#xff0c;很高兴能在CSDN与大家相遇&#xff01;✨ &#x1f680; 专栏介绍 这个专栏将专注于分享Java面试中的经典"八股文"知识点 &a…