在C ++中,如果我没记错的话,函数的任何参数都会按值传递,除非由&
限定,表示通过引用传递。
例如,
int double ( int i )
{
int twice = i * i;
return twice;
}
int main ( )
{
int i = 4;
int j = double(i);
return 0;
}
相当于
int i = 4;
// --- here's the part where the function runs ---
int temp = i;
int twice = temp * temp;
i = twice;
// -----------------------------------------------
并且它在C#中的工作方式相同,因为int
是数据类型或值类型(我听说过这两个术语)。< / p>
当事情变得不同的时候,你在C#中传入了所谓的引用类型或对象。在C ++中,如果传入class
而没有使用&
进行限定,则该函数就像使用参数的深层副本一样工作。
例如,C ++中的以下内容不会增加Charlie
的{{1}}。
Age
class Dude
{
pulic Dude ( name = "", age = 0 ) : Name(name), Age(age) { }
public string Name;
public int Age;
}
public void IncrementDudeAge ( Dude dude )
{
++dude.Age;
}
int main ( )
{
Dude Charlie = new Dude ( "Charlie", 69 );
IncrementDudeAge(Charlie);
std::cout << Charlie.Age; // prints 69
}
相当于
main
这与C#不同,因为在C#中,相同的代码会增加 Dude Charlie = new Dude ( "Charlie", 69 );
Dude temp = new Dude( "Charlie", 69 );
++temp.Age;
std::cout << Charlie.Age; // prints 69
:
Age
这段代码相当于像
这样的C ++代码public class Program
{
public static void IncrementDudeAge ( Dude dude )
{
++dude.Age;
}
public class Dude
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void Main ()
{
Dude Charlie = new Dude() { Name = "Charlie", Age = 69 };
IncrementDudeAge(Charlie);
Console.WriteLine(Charlie.Age); // prints 70
}
}
换句话说,在上面两段代码中,您传递了class Dude
{
pulic Dude ( name = "", age = 0 ) : Name(name), Age(age) { }
public string Name;
public int Age;
}
public void IncrementDudeAge ( Dude * dude )
{
++*dude.Age;
}
int main ( )
{
Dude Charlie = new Dude ( "Charlie", 69 );
IncrementDudeAge(&Charlie);
std::cout << Charlie.Age; // prints 70
}
的别名,这是指向Charlie
的内容的副本。在C ++中,该别名是实际的整数类型,而在C#中,您可以将其视为别名。
因为在这两种情况下它都指向Charlie
的副本,如果您尝试重新分配他,则不会影响实际的Charlie
:
Charlie
和
public void IncrementDudeAge ( Dude * dude )
{
dude = new Dude ( "Charlie", 70 );
}
什么都不做。这就是在C#中使用 public static void IncrementDudeAge ( Dude dude )
{
dude = new Dude() { Name = "Charlie", Age = 70 };
}
或在C ++中使用ref
或**
的地方。
我对所有事情都是正确的吗?
答案 0 :(得分:3)
tl;博士:是的。
我对C ++并不熟悉,但是AFAICS,你的解释看起来是正确的。
在C♯中,有两个独立的轴要考虑:
注意单词&#34; reference&#34;使用两次,上面有两种不同的含义。如果我们想删除这个词,我们可以大致重写如下:
Pass-by-value是C♯中的默认值。如果你没有做任何特别的事情,那么Argument传递总是传递值,没有例外。如果显式使用ref
关键字定义定义和呼叫网站,则可以请求按引用传递。 (还有out
关键字,它是一种特殊的传递引用,用于输出参数,不允许被调用者取消引用并且需要在每个可能的返回路径中初始化引用。)
因此,传值和传递引用之间的区别在于传递参数的方式。
值类型和引用类型之间的区别在于传递的:使用值类型,传递值本身,使用引用类型,正在传递指向值的指针。由于引用类型始终使用指针,值类型总是没有,因此没有用于引用或解除引用指针的特殊语法,所有这些都是隐式的。但它就在那里。
这为我们提供了四种可能的组合:
struct MutableCell
{
public string value;
}
class Program
{
static void ArgumentPassing(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
{
foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
foo = new string[] { "C# is not pass-by-reference." };
bar.value = "For value types, it is *not* call-by-sharing.";
bar = new MutableCell { value = "And also not pass-by-reference." };
baz = "It also supports pass-by-reference if explicitly requested.";
qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
}
static void Main(string[] args)
{
var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };
var corge = new MutableCell { value = "For value types it is pure pass-by-value." };
var grault = "This string will vanish because of pass-by-reference.";
var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };
ArgumentPassing(quux, corge, ref grault, ref garply);
Console.WriteLine(quux[0]);
// More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.
Console.WriteLine(corge.value);
// For value types it is pure pass-by-value.
Console.WriteLine(grault);
// It also supports pass-by-reference if explicitly requested.
Console.WriteLine(garply.value);
// Pass-by-reference is supported for value types as well.
}
}
答案 1 :(得分:2)
是的,你是对的。可以指出一些微小的措辞问题,但所有观察结果都可以。