我正在学习C ++的基础知识,来自.NET世界(C#)。
我发现一个有趣的主题是 const 关键字及其与指针的用法(const指针/指向const的指针)。
我想知道是否有任何C#语言等同于C ++的const指针/指针? (我知道C#没有指针,我正在考虑引用C#中类似指针的类型。)
另外,出于兴趣,如果没有这样的等价物,那么不包括这样一个特征的决定是什么?
答案 0 :(得分:5)
没有直接等同于在C#中将引用作为“const”传递,但是有其他方法可以实现其目的。最常见的方法是使您的引用类完全不可变(一旦构造,其状态永远不会更改)或将其作为不可变的公共接口传递。后者最接近'const'参数契约的意图(我给你一些参考,所以你可以使用它,但我要求你不要改变它。)一个行为不端的客户可能'当然,将公共界面抛弃为可变形式,但它仍然明确了意图。你也可以在C ++中“抛弃”const,认为这很少是一个好主意。
C ++中的另一件事是,当您知道传递的引用的生命周期在范围上有限时,您通常更愿意传递为const。 C ++通常遵循在方法范围内在堆栈上创建和销毁对象的模式,因此对这些对象的任何引用都不应该在该范围之外持久化(因为在它们超出范围之后使用它们可能会导致真正令人讨厌的堆栈损坏崩溃。) const引用不应该被改变,所以它是一个强烈的暗示,将它存储在某个地方以便稍后引用将是一个坏主意。使用const参数的方法很有希望传递这些范围的引用是安全的。由于C#从不允许存储对堆栈中对象的引用(在参数之外),因此这不是一个问题。
答案 1 :(得分:2)
C#中的常量对象(即readonly
)的概念(或者就此而言是Java)大致对应于C ++中的object *const
,即指向非常量对象的常量指针。
有几个原因 - 一个正确指定const
并使其在语言中有用非常困难。以c ++为例,你必须定义许多方法两次,只需对签名进行少量更改,即const_cast,const仅应用于浅层等事实。
所以C#寻求简单的解决方案,使语言更简单 - D
采用传递常数正确性等方式,正如我所理解的那样(从来没有在D中写过一行,所以请用盐粒)。
C#/ Java中的常用解决方案是使用不可变类,可能使用构建器模式,或者禁止更改的简单包装器(例如,包装另一个集合的所有不可修改的集合,并为像mut这样的变异方法抛出异常)。
答案 2 :(得分:1)
8,000,000年后,但是C#7.2使用的“ in”关键字有点像const。它告诉编译器按引用传递结构或原始变量(如ref或out),但该方法将不会修改该变量。
public void DoSomething(in int variable){
//Whatever
}
在功能上等同于C ++。
void Foo::DoSomething(int& const variable){
//Whatever
}
甚至可以说
void Foo::DoSomething(int const * const variable){
//Whatever
}
根据MSDN,在C#中执行此操作的主要原因是告诉编译器它可以通过引用传递变量,因为它不会被修改。传递大型结构时,这可能会带来更好的性能
关于常量指针,请参见以下答案:Difference between const. pointer and reference?
换句话说,对于大多数应用程序,C ++中的引用与const指针非常相似。但是,有关如何使用它们,C#中的引用更接近C ++中的指针。
可以重新实例化作为参数传递给C#中的方法的引用对象(例如,从对象实例A到对象实例B),但是B的生存期仅在方法范围内,并且一旦返回给调用方就被丢弃(因为指针本身通过值传递),并且调用者的引用始终是A。在这种意义上,您可以自由地在C#中传递引用,并且知道不能使它们指向不同的对象(除非使用ref / out关键字)。
C#示例-
class Foo
{
//Stateful field
public int x;
//Constructor
public Foo()
{
x = 6;
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
foo.x = 8;
VarTestField(foo);
Console.WriteLine(foo.x);
RefTestField(ref foo);
Console.WriteLine(foo.x);
}
//Object passed by reference, pointer passed by value
static void VarTestField(Foo whatever){
whatever = new Foo();
}
//Object passed by reference, pointer passed by reference
static void RefTestField(ref Foo whatever){
whatever = new Foo();
}
}
输出:
8
6
因此,不能,不能在C#中声明常量指针。尽管如此,明智地使用经过验证的设计模式,算法和OOP基础知识,以及语言的内置语法,您仍可以实现所需的行为。