reference in c++ and c#

本文最后更新于:2022年7月8日 下午

浅谈一下C#与C++中引用的区别

C# 中有两种类型:引用类型和值类型。 引用类型的变量存储对其数据(对象)的引用,而值类型的变量直接包含其数据。 对于引用类型,两种变量可引用同一对象;因此,对一个变量执行的操作会影响另一个变量所引用的对象。 对于值类型,每个变量都具有其自己的数据副本,对一个变量执行的操作不会影响另一个变量(in、ref 和 out 参数变量除外——

in 关键字会导致按引用传递参数,但确保未修改参数。 它让形参成为实参的别名,这必须是变量。 换而言之,对形参执行的任何操作都是对实参执行的。 它类似于 refout 关键字,不同之处在于 in 参数无法通过调用的方法进行修改。 out 参数必须由调用的方法进行修改,这些修改在调用上下文中是可观察的,而 ref 参数是可以修改的, 同时ref 要求在传递之前初始化变量。)

按值传递引用类型

引用类型的变量不直接包含其数据;它包含对其数据的引用。 如果按值传递引用类型参数,则可能更改属于所引用对象的数据,例如类成员的值。 但是,不能更改引用本身的值;例如,不能使用相同引用为新对象分配内存,并将其保留在方法外部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class PassingRefByVal
{
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}

static void Main()
{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);

Change(arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: 888
*/

在C++中,结果如下:

如图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <vector>
#include <iostream>
using namespace std;

void changeArray(std::vector<int> a) {
for (size_t i = 0; i < a.size(); ++i)
{
cout<<a[i]<<" ";
}
cout<<"\n";
a[0] = 999;
a = vector<int>{ -1,23,4,5 };
std::cout << a[0] << endl;
}
int main() {
vector<int> a{ 1,2,3 };
std::cout << a[0] << endl;
changeArray(a);
std::cout << a[0] << endl;
}

输出为

1
2
3
4
1
1 2 3
-1
1

可以看出C#自动传递引用类型,只不过按照值传递;而C++则是调用复制构造函数,直接产生一个新的数组,对函数外没有影响。

按引用传递引用类型

除了 ref 关键字添加到方法标头和调用,以下示例与上述示例相同。 方法中所作的任何更改都会影响调用程序中的原始变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class PassingRefByRef
{
static void Change(ref int[] pArray)
{
// Both of the following changes will affect the original variables:
pArray[0] = 888;
pArray = new int[5] {-3, -1, -2, -3, -4};
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}

static void Main()
{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);

Change(ref arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: -3
*/

C++如下:(在上面C++的代码中加了一个&)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void changeArray(std::vector<int>& a) {
for (size_t i = 0; i < a.size(); ++i)
{
cout<<a[i]<<" ";
}
cout<<"\n";
a[0] = 999;
a = vector<int>{ -1,23,4,5 };
std::cout << a[0] << endl;
}
int main() {
vector<int> a{ 1,2,3 };
std::cout << a[0] << endl;
changeArray(a);
std::cout << a[0] << endl;
}

输出:

1
2
3
4
1
1 2 3
-1
-1

C++ 应该是没有值类型和引用类型的说法的(或者说不存在与 C# 的引用类型和值类型相对应的概念)。但是 C++ 类型的行为默认是 C# 中值类型的行为。

比如函数传递参数时,C++ 和 C# 的值类型都会把参数完整复制一份。C++ 往往用传递 const 引用的方式来省去复制的开销。而 C# 可以用 ref 关键词来传递值类型的引用。

结语

上述只是简单描述了其区别,但对原理尚未搞清楚,希望等到对引用了解深入以及进一步学习后再来看C++与C#的区别。

参考链接:

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/ref

https://uint128.com/2021/05/08/C-%E5%92%8CC-%E7%9A%84%E5%80%BC%E7%B1%BB%E5%9E%8B%E4%B8%8E%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B/


reference in c++ and c#
https://blogoasis.github.io/post/8a2f0ada.html
作者
phInTJ
发布于
2022年6月14日
许可协议