Const Qualifiers and You
 
注意:与所有关于范围的事情一样,Const限定词可能有点难以理解。在尝试了解Const Qualfiers之前,您应该对变量范围有一个透彻的了解。

还要注意我的陈词滥调,我选择的是因为它的意思。

什么是Const限定词? Const限定词是最近添加到语言的功能(fbc 0.18.3);它们是C ++的标准部分,现在它们也存在于FreeBasic中。Const限定符是另一种形式的保护 - 它们允许一些“变量”像常量一样对程序的某些部分起作用,换句话说,程序的某些部分被允许访问(读取)但不能修改它们。只是另一种类型的安全,真的,但非常有用的一个。特别是,它们在OO情况下非常有用,但即使您对OOP不感兴趣,您也可以在某种程度上受益。

FreeBasic中的Const限定符本质上是数据类型声明的扩展,它们可以与Dim,UDT成员和过程参数一起使用。一般来说,您将它放在变量的数据类型声明的“As”部分之后:

Dim As Const Integer my_const_int = 5


(顺便说一句,在本教程中,我只使用整数和整数Ptrs作为例子 - 然而,Const限定符should 与所有其他变量类型的工作方式相同,包括类型,枚举以及声明某事的其他任何变量。如果由于任何原因,它不是,这可能是一个错误,你应该报告。)

注意在这种情况下,我们可以更改一次 - 当我们创建它。但之后,您可能不会再更改它。事实上,你must 初始化它 - 编译器会给你一个错误,如果你没有(有趣的是,你被允许设置等于“任何”,内容不能保证,可以是任何东西)。但是,你可能不会做任何改变它的事情。如果你尝试做这样的事情,它会给你一个错误:

my_const_int = 3


然而,由于这不会改变任何变量,你可以做

Print my_const_int


现在这一切都很好,但是与Const的正常使用并没有什么不同。也就是说,以下两行到目前为止似乎意味着,对于所有实际目的,同样的事情:

Dim As Const Integer my_const_int = 5
Const my_int As Integer = 5


他们吗不完全的。您可以看到,Const限定符允许您创建作为变量的const,但不能修改它们。这意味着你可以把它们放在“类型”和其他地方。此外,您可以将它们放在子/函数声明中 - 这是它们存在的一个非常关键的原因:

Sub my_sub (some_num As Integer)
End Sub


通常,函数允许修改发送给它们的变量。当然,无论他们修改原始变量还是仅仅修改变量的本地副本取决于是否使用ByVal或ByRef(当然指针是完全不同的),但通常可以修改变量。这可能是不希望的,无论出于什么原因,并且Const限定符存在以防止这种情况。在上面给出的函数中,some_num可以被函数修改。通常它只是一个被修改的本地副本,这是很好的,因为它不会影响原始的Const Integer,但是如果我们声明这样的函数呢?

Sub my_sub (ByRef some_num As Integer)
End Sub


现在my_sub可以直接访问你传递给它的任何变量,因此,你不能做这样的事情

my_sub(my_const_int)


为什么?只是因为该函数可能会修改变量。当然,我们不知道它会是否可能,所以我们不能这样做。事实上,如果您尝试编译的错误是“无效的转换/转换”。几乎就好像Const Integer是一个不同的变量类型,只有当它是ByRef的时候。在这种情况下,它会像尝试将一个字符串传递给整型参数(反之亦然)。但是如果没有通过ByRef,我们没有问题,因为这个函数不可能修改变量!

当然,如果我们这样做:

Sub my_sub (ByRef some_num As Const Integer)
End Sub


然后它编译得很好,但是如果你尝试在函数中执行以下操作,你会得到一个错误:

some_num = 3


为什么?再次,原始变量已经通过ByRef到sub。它现在在本地范围内,但是由于它是ByRef,对变量的任何修改都会修改原始的,这是不可能的。再次,完全可以创建一个变量的副本,并修改所有你想要的:

Dim As Integer copy_of_some_num = some_num
copy_of_some_num = 3


但是你不能修改some_num本身!

现在我们来指点他们呢?对于指针来说,这有点复杂;可以将指针itself 声明为Const,或者指针指向 - 甚至是BOTH!所以以下所有内容都是有效的:

Declare Sub my_sub_a (ByRef ptr_A As Const Byte Ptr)

Declare Sub my_sub_b (ByRef ptr_B As Byte Const Ptr)

Declare Sub my_sub_c (ByRef ptr_C As Const Byte Const Ptr)


第一个使它可以改变你想要的指针本身,而不是指针指向的数据(即使你改变*指针指向什么)。第二个允许你改变指针指向什么,但是你不能指出任何其他的东西。第三个不会让你改变指针指向OR或指针本身!在所有情况下,您可以制作一个指针的副本 - but it must be a Const Integer Ptr or a Const Integer Const Ptr since otherwise you would be able to change the contents of whatever the original pointer points to! 这是非常好的保护,防止任何被修改!

如果Const限定词的行为似乎有点奇怪,我会详细解释它如何决定什么是安全的,什么不是。实际上可以很快地总结:Const限定词旨在保护原始数据。它不在乎如果您制作数据副本,或更改该副本,它只是不希望您能够更改原始数据。记住这将帮助你很多。当然,它需要知道what 的原始数据,这就是为什么当有指针涉及到有很多不同的地方放置Const限定符(你甚至可以把它放在两倍或更多,取决于多少指针有!)只要你记得Const限定词是什么,你永远都不会有任何困难弄清楚哪里放置 - 或者即使你需要它(或者如果你需要not 使用它) )。

您也可以在UDT中使用Const限定符。实际上,它实际上是一个非常重要的事情,OOP(以类似于命名空间的方式,尽管不是OOP的直接部分,但是非常相关) - 但即使你不使用OOP,你仍然可以使用Const限定符你的类型我甚至不需要给你一个例子,因为现在很明显它是如何工作的,但这里是一个例子:

Type my_type
  As Const Integer t_int= 5
End Type

Dim As my_type t

t.t_int = 3


显然这不会编译,因为成员t_int是Const。此外,您还可以使用Const限定符声明该类型的变量(在这种情况下为t)。以下不会编译,因为t的所有成员都是Const:

Type my_type
  As Integer t_int= 5
End Type

Dim As Const my_type t

t.t_int = 3


至于OOP方面的事情(如果你对OOP不感兴趣,可以跳过这一部分) - 你可能想知道方法。调用时,方法隐式传递对象ByRef。有没有办法创建常量对象?当然!我们已经看到了但是一些对象的方法会修改对象,有些则不会。有区别吗答案是肯定的。截至2007年11月23日,我们现在有Const过程。这意味着你可以这样做:

Type my_object
  Public:
    Declare Sub modifier_sub ()
    
    'Subs that do not modify the object are declared Const...
    Declare Const Sub non_modifier_sub ()
  Private:
    some_num As Integer = 3
End Type

Sub my_object.modifier_sub ()
  this.some_num = 3
End Sub

Sub my_object.non_modifier_sub()
  Print this.some_num
End Sub

'Note that only Const objects must be initialized (though in this case the non-Const object will also be),
'just like variables.  Thus, you must either have a Constructor for the object, or else you must give all variables
'default initial values (as I did here), in which case the compiler makes a default constructor for you.
Dim As Const my_object t = my_object
Dim As my_object u

'Both of these will compile:
t.non_modifier_sub()
u.non_modifier_sub()

'...but the first of these will not compile, since non-Const methods of Const objects may not be called!
t.modifier_sub()
u.modifier_sub()

'Sleep so we can see the results
Sleep


再次,这个工作方式是基于简单的规则。由于隐式传递的副本通过ByRef,任何方法通常都可以修改对象的内容 - 如果对象被声明为Const,那就不应该发生!因此,基本上有两种方法。这两种在C ++文档页面中列出(在下面的参考文献中列出):有mutators和inspectors。突变体可能会修改对象,但检查员不会。因此,对于声明为Const的对象,只能使用这些对象的检查器方法 - 而所有方法可能被调用为非Const对象。检查器方法当然是声明为Const方法的方法。因此,对于Const对象,只能使用其Const方法。


这一切都很好,但是有些人可能会问 - 为什么我需要这个?那么一个直接的答案将是本教程的*范围*(嘿),所以我会反驳 - 为什么我们需要范围? Const限定符(和未来的Const方法)的原因与过程和模块中的范围的原因相同,以及在对象中隐藏变量的相同原因:因为我们想确定一些事情不会意外地改变在程序的中间,当我们最不期望的时候。有时我们希望事情发生变化,那就是我们don't 使用Const限定符。但是当你想要保持原样的时候,你可以使用Const限定符,你可以确定它不会改变(如果有危险的话,编译器不会编译代码)!这是定义Const,它是如何工作的,这是你使用它的原因!一般来说,这就是您使用any 范围控制或数据隐藏的原因。


一些最后的笔记
如果您使用Const限定词,请记住这是一个相对较新的功能。告诉我们什么是“错误”或“正确”的文档很少,所以通常需要一些实验。如果你觉得它做的事情不应该做(或不做某事,应该),一切手段报告在论坛!如果被其他人视为问题,请提交错误报告。但是,总的来说,它应该正如我所说的那样正常工作,所有给出的例子应该像我说的那样做(如果我说他们会的话,编译,如果我说不会编译的话)。当然,一个非常重要的事情是,它们不在最新的官方发行版中 - 你必须拥有最新的SVN版本才能工作(如果编译器给出了我在这里给出的示例之一的错误你会编译,那么你会知道你需要一个更新的版本)。

如果您对Const限定词有任何其他困难,请记住,即使没有文档,论坛上还有许多人了解并理解他们,并且可以帮助您解决任何问题。

如果你仍然不明白Const限定词,那么你可能是一个新手,他对范围并不太了解,而且没关系,你会随时随地学习。最终会创建一些这种功能的体面的文档,但直到那时,这是你所有的。记住:如果你不明白他们如何工作,你可能不需要它们。我有一个人在他们周围很久才编写好的程序,我可能会继续这样做,而不需要在任何地方使用它们。有特定的实例,当它们有用时,如果您了解这些实例,那么您可以在出现这些实例时使用它们。但是如果你不明白,那没关系

最后,这里有一些应该有帮助的链接。第一个是关于C ++中的Const限定符的C ++文档页面 - 当然,如果您理解C ++,它们也是有意义的,并且还讨论了我们还没有的东西(即Const方法)。然而,如果你知道任何C ++,这是一个很好的开始,所以如果你喜欢,请查看它。还有一个论坛主题的链接,其中我询问FreeBasic开发(并了解有关Const限定词),以及指向原始SourceForge功能请求页面的链接,其中最初要求将Const限定词作为功能:

http://www.parashift.com/c++-faq-lite/const-correctness.html
http://www.freebasic.net/forum/viewtopic.php?t=9975\u0026postdays=0\u0026postorder=asc\u0026start=0
http://sourceforge.net/tracker/index.php?func=detail\u0026aid=1480621\u0026group_id=122342\u0026atid=693199