昨天我正和一位同事谈论这件事,这让我想到了.Net的传递参考。
// C#
class Foo {}
static void Test(ref Foo foo) { ... };
static void Main()
{
Foo f;
Test(ref foo);
}
必须使用双重间接实现,因为我们正在更改指针的值。因为所有引用类型都是引用(指针)
// C#
static void Test(Foo foo) { ... }
static void Test(ref Foo foo) { ... };
等同于
// C++
void Test(Foo *foo);
void Test(Foo **foo);
但如果这是 VALUE 类型,我们实际上并不需要双重间接。所以我很好奇,如果
// C#
static void Test(ref int bar) { ... }
变为
// C++
void Test(int *bar);
// or
void Test(int **bar);
1/29/10更新: 阅读所有答案后,我意识到我对自己想要的内容并不十分清楚,而且因为将C ++投入到正在发生的事情中而误导我。我最感兴趣的是它是如何在CLR中实现的,以及JIT将如何为它生成程序集。感谢所有的答案,我从一个角度发现它们都是正确的,但我选择了一个最接近我所问过的思考的问题。
答案 0 :(得分:6)
考虑ref
的正确方法是存储位置的别名。因此,当你说
int x;
Foo(ref x);
和Foo
被声明为
void Foo(ref int y)
您要将x
和y
视为上述方法调用中相同位置的别名。
因此,C#中的void Foo(ref int y)
与C ++中的void Foo(int &y)
类似。
答案 1 :(得分:5)
引用不是指针。
Foo foo = new Foo();
这声明了一个“内存单元”,它包含对Foo实例的引用。然后它初始化Foo
的新实例并将引用存储在内存单元中。
Bar(Foo x) { x = new Foo(); }
这声明了一个带有Foo
参数的方法,该参数本质上是一个局部变量(如foo),当使用参数调用该方法时,该变量恰好被自动分配。
方法中的语句创建Foo
的新实例,并将对实例的引用存储在内存单元x
中。内存单元foo
保持不变。
Bar(foo);
通过将存储在单元格Bar
中的值复制到存储单元格foo
- 按值调用来调用x
。
如果您编写int
而不是Foo
,则会发生同样的情况,除了存储在存储单元格中的值不是参考值而是实际值。
Qux(ref Foo y) { y = new Foo(); }
这声明了一个带有Foo&
参数的方法,该参数本质上是一个局部变量,它包含一个存储单元的地址,该存储单元保存对类型为Foo
的对象的引用。
Qux(ref x);
通过将Qux
设置为内存单元格y
的地址 - 按引用调用来调用x
。
Qux
中的语句创建了Foo
的新实例,并将对象的引用存储在位于地址y
的内存单元格中(这是{{1}的地址1}})。因此foo
被赋予对新实例和更改的引用。
当foo
为Foo
时,恰好相同,除了存储在通过引用传递的内存单元格中的值不是对象的引用而是实际值。
答案 2 :(得分:5)
在C#中,当你有方法时
void M(ref int f) { }
你称之为
int x = 123;
M(ref int x):
这是如何工作的?
逻辑,这意味着“x和f指的是相同的存储位置”。
我们在CLR 中实际实现的方式是f类型为“可以包含整数的变量的托管引用”。我们将局部变量x的托管地址传递给M。
C ++中的类比将是一个带有& int的方法 - 对可以包含int的变量的引用。
这是清楚的吗?
答案 3 :(得分:0)
参考是&不是*你用指针混淆它。所以这意味着它将被传递为:
void Test(Foo &bar);
答案 4 :(得分:0)
我非常确定像int这样的值类型只使用单个级别的间接。
答案 5 :(得分:0)
MyClass
- > MyClass*
(或实际上,shared_ptr<MyClass>
)ref
- &gt; &
C#:
void doSomething(int myInt);
void doSomethingElse(ref int myIntRef);
void doSomething(Foo foo);
void doSomethingElse(ref Foo fooRef);
C ++:
void doSomething(int myInt);
void doSomethingElse(int& myInt);
void doSomething(Foo* fooPtr);
void doSomething(Foo*& fooPtrRef);
答案 6 :(得分:0)
您可能想要检查它在C ++ / CLI中的实现方式。我在一本书中找到了很好的解释:Expert C++/CLI: NET for Visual C++ programmers,第83页。
Foo^
被定义为“指向Foo的托管指针”,相当于UnmanagedFoo*
。
int%
和Foo^%
是“托管参考”,它们相当于int&
和UnmanagedFoo*&
。