免责声明:我知道有两个关于const-correctness有用的问题,但是,没有人讨论过如何在C++中使用const-correctness 而不是其他编程语言.此外,我对这些问题的答案不满意.
我现在使用了一些编程语言,在C++中让我烦恼的一件事就是const-correctness的概念.在Java,C#,Python,Ruby,Visual Basic等中没有这样的概念,这似乎对C++非常具体.
在你推荐我使用C++ FAQ Lite之前,我已经阅读了它,但这并不能说服我.完全有效,可靠的程序一直用Python编写,没有const关键字或等价物.在Java和C#中,对象可以声明为final(或const),但是没有const成员函数或const函数参数.如果函数不需要修改对象,则它可以采用仅提供对象的读访问权的接口.该技术同样可以在C++中使用.在我工作的两个真实的C++系统上,几乎没有使用const,一切都运行正常.因此,对于让const污染代码库的有用性,我还远没有卖掉.
我想知道在C++中它是什么让const成为必要,而不是其他编程语言.
到目前为止,我只看到了必须使用const的一种情况:
#include <iostream>
struct Vector2 {
int X;
int Y;
};
void display(/* const */ Vector2& vect) {
std::cout << vect.X << " " << vect.Y << std::endl;
}
int main() {
display(Vector2());
}
Run Code Online (Sandbox Code Playgroud)
Visual Studio接受使用const注释掉的编译,但是使用警告C4239时,使用非标准扩展.所以,如果你想要传递临时代码,避免副本和保持标准兼容的语法简洁,你必须通过const引用,不管它.不过,这更像是一个怪癖,而不是一个根本原因.
否则,实际上不存在必须使用const的情况,除非与使用const的其他代码连接.在我看来,康斯特似乎不是一个自以为是的瘟疫,它蔓延到它接触到的一切:
const在C++中工作的原因是因为你可以把它丢弃.如果你不能把它扔掉,那么你的世界就会糟透了.如果声明一个采用const Bla的方法,则可以将它传递给非const Bla.但如果是相反的方式你不能.如果声明一个采用非const Bla的方法,则不能将它传递给const Bla.所以现在你被卡住了.所以你逐渐需要一个不是const的所有东西的const版本,你最终得到了一个阴影世界.在C++中,你可以使用它,因为与C++中的任何东西一样,无论你是否想要这个检查,它都是纯粹可选的.如果你不喜欢它,你可以打破常量.
Anders Hejlsberg(C#架构师),CLR设计选择
与继承者实现一个抽象的getter-only属性相比,拥有readonly字段有什么优点和缺点(在这里使用C#作为例子,但我想这并不重要).
以下是两种方法:
只读字段; 继承者必须在构造函数中注入值
interface IFace {
public int Field { get; }
}
abstract class Base : IFace {
private readonly int field;
protected Base(int field) {
this.field = field;
}
public int Field { get { return this.field; } }
}
class Impl {
public Impl() : base(1) {
}
}
Run Code Online (Sandbox Code Playgroud)抽象的getter-only属性; 继承者必须实现该属性
interface IFace {
public int Field { get; }
}
abstract class Base : IFace {
// default constructor can be used
public abstract int …Run Code Online (Sandbox Code Playgroud)初步说明:
这个问题不打算用于破坏.NET,也不打算讨论战争,如果存在"致命异常"这样的事情--Java的设计者清楚地认为存在,.NET设计者要么不这么认为,不知道否则,或者可能存在异常层次结构的另一个(技术)原因.
我最感兴趣的是,是否有任何MS设计人员的设计文档或声明,为什么.NET层次结构就像今天这样.疯狂的猜测和猜测会得到不好的答案.一致的论点/例子为什么没有这样的事情(可分类的)致命异常当然可以得到有效的答案,尽管我一定会不同意它们.但是,与评论相反,我保证不会与任何有凝聚力的答案争论;-)另一类答案可以证明Java的Error类型分类是一个坏主意/在Java实践中不起作用,从而隐含地显示为什么.NET不需要它.:-)
在努力成为一名经验更丰富的C#程序员的过程中,我注意到在.NET异常层次结构中我认为相当奇怪(*)的东西:
所有抛出类型的基类是Exception(好吧,基本上无论如何).
具体而言,许多例外直接从推导出Exception和进一步分类成SystemException- >等似乎相当无意义有点任意的.
作为一个例子,对我来说特别奇怪SEHException的ExternalExpection是,SystemException当它真的看起来更像是一种崩溃和烧伤的错误时,它就是a -a is-a .
虽然在Java中没有过多的经验,但我发现Java与wrt的区别.该Error类型与"正常" Exception,使有很大的意义.当然可以讨论细节,但是.NET/ C#甚至没有尝试这种方法似乎很奇怪.
C#成名的Eric Lippert 在分类异常方面有一个很好的部分,我大多赞同这一点,这让我更加想知道为什么.NET甚至没有试图为"致命异常"提供一个桶.
通过"致命异常"我基本上提到了Lippert先生描述的相同概念:
致命的例外不是你的错,你不能阻止他们,你不能明智地清理它们....
注意:最重要的是,它们很可能也可能也不是您调用引发异常的操作的错误.
......他们几乎总是发生,因为这个过程深深地病了,并且即将摆脱痛苦.内存不足,线程中止等.抓住这些是绝对没有意义的,因为你的微不足道的用户代码所做的一切都无法解决问题.让你的"终极"块运行并希望最好.(或者,如果你真的很担心,快速失败并且不要让最后的块运行;在这一点上,它们可能会让事情变得更糟.但这是另一天的主题.)
我会注意到,对于某些致命异常来说,技术上就像任何其他异常一样.你应该能够在适当的时候捕获它 - 只是99%的代码根本不适合处理它们.
以Lipperts先生为例:假设我调用一个函数来打开一个可以引发各种异常的文件.如果我抓到其中任何一个,我想要做的就是报告打开文件失败,原因为X并继续正确.但是,如果打开一个文件引发一个ThreadAbortedException,则报告任何内容没有意义,因为文件打开操作失败,但是一些代码中止当前线程并在假设FileNotFoundException不同的情况下处理它在绝大多数情况下都有意义.
评论者似乎认为只有捕获网站才能真正判断某些内容是否"致命"而且之前的分类是否合适,但我强烈怀疑 …