C++指针和C#引用之间的关系。

本文探讨了C#中引用类型与值类型的区别,特别是引用类型如何类似C++中的指针,并通过示例解释了如何在函数中正确交换引用类型对象。
问题是什么
刚接触C#不久,对于值类型和引用类型的区别还是有点糊涂。后来看了一个不能工作的Swap()(下面有示例)方法之后,才发现,其实引用类型相当于C/C++中的指针——因为有声明:“string aStr = null;”是正确的。为了让自己以后可以追溯一下,所以把今天的理解记录下来,写在这里。

如何理解
C#中关于引用类型的定义是这样的:
“……值类型与引用类型的基本区别是他们在内存中的存储方式。……引用类型变量的地址存放在栈上,但实际的对象存放在堆上。……”
 
在上一篇文章里我说过,指针其实是一个ulong,从上面的描述中可以看出,引用类型其实也是一个ulong(地址),也就是说,“Object obj;”中,obj被分成两部分,一部分是其地址,另一部分是真正的Object实例。这两部分紧密联系在一起,形成一个引用类型对象。
 
引用类型的定义暗示我们,C#中引用类型相当于C++的指针,只不过C#语言本身作了一些工作,将指针和其指向的对象紧密地联系在一起了。只不过我们无法通过强制类型转换来获取这个值——也许有,但是我比较菜,不知道,呵呵。另外,引用类型的定义还暗示我们,C/C++函数调用时以传值方式传递参数的规则,在C#中同样有效。最简单的例子:
// C# code. Non dereferencing.
public void Swap<T>(T lhs, T rhs)
{
    T temp = lhs;
    lhs = rhs;
    rhs = temp;
}
调用该函数结果是什么样子呢?运行一下下面的代码就知道结果:传进去的引用类型的对象根本就没有改变(以string为例):
string a = "aaaa";
string b = "bbbb";
Swap<string>(a, b);
System.Console.WriteLine("a = " + a + ", b = " + b);
输出结果:a = aaaa, b = bbbb
 
因为实际上是对地址进行操作,传入的参数就是地址,因此可以将其翻译成C++(方便起见,使用int类型):
// C++ code. Non dereferencing.
template <class T>
void Swap(T * lhs, T * rhs)
{
    T * ptemp = lhs;
    lhs = rhs;
    rhs = ptemp;
}
这个函数也不能达到交换实参的目的,因为此处操作的是地址,与上一个例子一样。也就是说,C/C++和C#中函数调用时以传值方式传递参数。
 
那么为什么不是与C++的引用相似呢?可以看以下代码:
// C++ code
template <class T>
void Swap(T& lhs, T& rhs)

{
    int temp = lhs;
    lhs = rhs;
    lhs = temp;
}
对这个函数的调用将正确的交换两个实参。
 
C#要想通过函数调用来修改引用类型的对象,有两种方式:
1、dereference该引用以获取实际对象,即改变存放在堆上的对象本身,而不是存放在栈上的地址(没有进行dereference),这与C++的指针是相同的,也是前两个例子说明的问题。用deference的话,而且T实现了拷贝自身的方法,那么实现如下:
// C# code. Dereferencing.
// NOTE: T must have CopyTo() method.
public void Swap<T>(T lhs, T rhs)
{
    T temp = new T();
    lhs.CopyTo(temp);
    rhs.CopyTo(lhs);
    temp.CopyTo(rhs);
}
翻译成C++,就是如下代码:
// C++ code. Dereferencing.
// NOTE: T must have operator "=" overloaded.
template <class T>
void Swap(T * lhs, T * rhs)
{
    int temp = *lhs;
    *lhs = *rhs;
    *rhs = temp;
}

2、使用ref修饰符(从另一个角度说明C#引用的行为更像C++的指针),如下:
//可以工作的Swap
// NOTE: T doesn't need to have CopyTo() method implemented.
//       If you don't need to modify the reference itself, "ref" is not needed.

private void Swap<T>(ref T lhs, ref T rhs)

{

    T temp = lhs;

    lhs = rhs;

    rhs = temp;

}
原因很简单,使用了ref,将其翻译成C++就是:
/ C++ code. Dereferencing.
// NOTE: T doesn't need to have operator "=" overloaded.
template<T>
void Swap(T **lhs, T **rhs)
{
    T * temp = *lhs;
    *lhs = *rhs;
    *rhs = temp;
}

至于这里面涉及到的应该使用引用还是指针的问题,那就是另外一个话题了。关于指针本身,可以参考“ 指针是通往地狱的捷径”。

PS:由于对C#水平实在太浅,理解难免出现偏差,任何错误,请大虾指正!上述代码均为合法代码。
转载自: http://blog.sina.com.cn/s/blog_4cbdf19501008jay.html
### 设计目标 C++ C# 均属于现代编程语言中的重要成员,但它们的设计目标有所不同。C++ 被设计为一种通用的、高效的编程语言,能够支持多种编程范式,包括面向对象编程 (OOP)、过程化编程泛型编程[^2]。它的主要目的是提供高性能的同时保持对底层硬件的强大控制力。 相比之下,C# 的设计更注重于简化开发流程并提升生产力。作为一种现代化的语言,C# 主要服务于企业级应用程序开发,强调易用性、安全性跨平台兼容性。它通过减少手动资源管理错误处理的工作量来降低复杂度[^1]。 --- ### 语法特点 #### 面向对象编程 两者均完全支持面向对象编程的核心概念——类、继承、多态封装。然而,在实现方式上有所差异: - **C++**: 提供了灵活的机制让开发者自行决定如何管理内存(如使用 `new` `delete`),同时也允许直接操作指针。这些功能赋予程序员极大的自由度,但也增加了潜在的风险难度[^3]。 - **C#**: 自动化的垃圾回收器负责清理不再使用的对象,从而减轻了开发者的负担。此外,虽然也提供了访问修饰符等功能,但它隐藏了许多低级别的细节以便专注于高层逻辑编写。 #### 数据类型安全性 - 在数据类型的定义方面,C++ 更接近机器层面,允许用户定义自己的模板元编程结构等高级特性; - 而 C# 则内置了一些额外的安全保障措施,例如数组越界检查以及强制性的异常捕获机制,有助于防止常见的运行时错误发生[^4]。 --- ### 应用场景 由于各自独特的性质决定了它们适合解决不同类型的问题领域: - 对于需要极致性能或者深入操作系统内部工作的场合来说,比如游戏引擎制作或是嵌入式设备驱动程序编制,则通常会选择采用 C++ 来完成因为其具备更好的执行效率及更大的灵活性[^2]。 - 如果目标是快速构建大型业务解决方案或者是 Web 应用服务端架构的话,那么基于 .NET 平台之上构建起来更为便捷可靠的 C# 就成为了首选方案之一。 ```csharp // 示例:简单的 C# 控制台应用程序 using System; class Program { static void Main() { Console.WriteLine("Hello, world!"); } } ``` ```cpp // 示例:简单的 C++ 控制台应用程序 #include <iostream> int main(){ std::cout << "Hello, world!" << std::endl; return 0; } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值