4

我正在学习来自 .NET 世界 (C#) 的 C++ 基础知识。

我发现有趣的一个主题是const关键字及其与指针的用法(const 指针/指向 const 的指针)。

我想知道是否有任何 C# 语言等效于 C++ 的 const 指针/指向 const 的指针?(我知道 C# 没有指针,我正在考虑将引用作为 C# 中的类指针类型)。

另外,出于兴趣,如果没有这样的等价物,那么不包括这样的功能背后的决定是什么?

4

3 回答 3

6

在 C# 中没有直接等同于将引用作为“const”传递,但有其他方法可以实现其目的。最常见的方法是让你的引用类要么完全不可变(一旦构建,它的状态就永远不会改变),或者将它作为不可变的公共接口传递。后者最接近 'const' 参数合同的意图(我给你一个参考,以便你可以使用它,但我要求你不要更改它。)表现不佳的客户可能'当然,将公共接口抛弃为可变形式,但它仍然清楚地表明了意图。您也可以在 C++ 中“抛弃” const,认为这很少是一个好主意。


C++ 中的另一件事是,当您知道要传递的引用的生命周期在范围内受到限制时,您通常更愿意将其作为 const 传递。C++ 通常遵循在方法范围内的堆栈上创建和销毁对象的模式,因此对这些对象的任何引用都不应该在该范围之外持久化(因为在它们超出范围后使用它们可能会导致非常讨厌的堆栈损坏崩溃。) const 引用不应该被改变,因此强烈暗示将其存储在某个地方以供以后引用将是一个坏主意。带有 const 参数的方法承诺传递这些作用域引用是安全的。由于 C# 不允许在堆栈上(参数之外)存储对对象的引用,所以这不是一个问题。

于 2012-12-24T20:29:02.943 回答
2

C#(或Java)中的常量对象(即readonly)的概念大致对应object *const于C++,即指向非常量对象的常量指针。

它有几个原因 - 因为const正确指定并使其在语言中有用是相当困难的。以 c++ 为例,您必须定义很多方法两次,只需对签名进行很小的更改,还有 const_cast、const 仅应用于浅层的事实等。

因此,C# 采用了一种简单的解决方案来使语言更简单——D按照我的理解,通过传递 const 的正确性等等采取了另一种方式(从来没有在 D 中写过一行,所以请谨慎对待)。

C#/Java 中通常的解决方案是拥有不可变的类,可能使用构建器模式,或禁止更改的简单包装器(例如,所有不可修改的集合包装另一个集合并为诸如 add 之类的变异方法抛出异常)。

于 2012-12-24T20:28:11.627 回答
1

8,000,000 年后,但 C# 7.2 使用类似于 const 的“in”关键字。它告诉编译器通过引用(如 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# 中这样做的主要原因是告诉编译器它可以通过引用传递变量,因为它不会被修改。这允许在传递大型结构时可能获得更好的性能

关于常量指针,请参阅此答案:const 之间的区别。指针和参考?

换句话说,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 基础知识,以及语言的内置语法,您可以实现所需的行为。

于 2019-09-10T16:46:19.850 回答