荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Second (石开), 信区: Program
标  题: C++语言常见问题解答(2-11)Const正确性
发信站: 荔园晨风BBS站 (Sun Sep 23 10:48:54 2001), 转信

=============================
■□ 第11节:Const 正确性
=============================

Q45:什麽是 "const correctness"?

好问题。

「常数正确性」乃使用 "const" 关键字,以确保常数物件不会被更动到。譬如:若

"f()" 函数接收一个 "String",且 "f()" 想确保 "String" 不会被改变,你可
以:

*传值呼叫 (pass by value): void  f( String  s  )  { /*...*/ }
*透过常数参考 (reference):  void  f(const String& s  ){ /*...*/ }
*透过常数指标 (pointer)  :  void  f(const String* sptr) { /*...*/ }
*但不能用非常数参考  :    void  f( String& s   )  { /*...*/ }
*也不能用非常数指标  :    void  f( String* sptr)    { /*...*/ }

在接收 "const String&" 参数的函数里面,想更动到 "s" 的话,会产生个编译期
的错误;没有牺牲任何执行期的空间及速度。

宣告 "const" 参数也是另一种型别安全方法,就像一个常数字串,它会“丧失”各

种可能会变更其内容的行为动作。如果你发现型别安全性质让你的系统正确地运作
(这是真的;特别是大型的系统),你会发现「常数正确性」亦如是。

========================================

Q46:我该早一点还是晚一点让东西有常数正确性?

越越越早越好。

延後补以常数正确性,会导致雪球效应:每次你在「这儿」用了 "const",你就得在

「那儿」加上四个以上的 "const"。

========================================

Q47:什麽是「const 成员函数」?

一个只检测(而不更动)其物件的成员函数。

        class Fred {
        public:
          void f() const;
        };      // ^^^^^--- 暗示说 "fred.f()" 不会改变到
"fred"

此乃意指:「抽象层次」的(用户可见的)物件状态不被改变(而不是许诺:该物件

的「每一个位元内容」都不会被动到)。C++ 编译器不会对你许诺「每一个位元」这

种事情,因为不是常数的别名(alias)就可能会修改物件的状态(把 "const" 指标

黏上某个物件,并不能担保该物件不被改变;它只能担保该物件不会「被该指标的动

作」所改变)。

【译注】请逐字细读上面这句话。

"const" 成员函数常被称作「查询子」(inspector),不是 "const" 的成员函数则

称为「更动子」(mutator)。

========================================

Q48:若我想在 "const" 成员函数内更新一个「看不见的」资料成员,该怎麽做?


使用 "mutable" 或是 "const_cast"。
【译注】这是很新的 ANSI C++ RTTI (RunTime Type Information) 规定,Bor
land
        C++ 4.0 就率先提供了 const_cast 运算子。

少数的查询子需要对资料成员做些无害的改变(譬如:"Set" 物件可能想快取它上一

回所查到的东西,以加速下一次的查询)。此改变「无害」是指:此改变不会由物件

的外部介面察觉出来(否则,该运作行为就该叫做更动子,而非查询子了)。

这类情况下,会被更动的资料成员就该被标示成 "mutable"(把 "mutable" 关键字

放在该资料成员宣告处前面;也就是和你放 "const" 一样的地方),这会告诉编译

器:此资料成员允许 const 成员函数改变之。若你不能用 "mutable" 的话,可以

"const_cast" 把 "this" 的「常数性」给转型掉。譬如,在 "Set::lookup() co
nst"
里,你可以说:

        Set* self = const_cast(this);

这行执行之後,"self" 的位元内容就和 "this" 一样(譬如:"self==this"),但

是 "self" 是一个 "Set*" 而非 "const Set*" 了,所以你就可以用 "self"
去修改
"this" 指标所指向的物件。

========================================

Q49:"const_cast" 会不会丧失最佳化的可能?

理论上,是;实际上,否。

就算编译器没真正做好 "const_cast",欲避免 "const" 成员函数被呼叫时,会造成

暂存器快取区被清空的唯一方法,乃确保没有任何「非常数」的指标指向该物件。这

种情况很难得会发生(当物件在 const 成员函数被启用的□围内被建立出来;当所

有非 const 的成员函数在物件建立间启用,和 const 成员函数的启用被静态系结

;当所有的启用也都是 "inline";当建构子本身就是 "inline";和当建构子所呼叫

的任何成员函数都是 inline 时)。

【译注】这一段话很难翻得好(好啦好啦!我功力不足... :-< ),所以附上原文:

Even if a compiler outlawed "const_cast", the only way to avoid f
lushing
the register cache across a "const" member function call would be
to
ensure that there are no non-const pointers that alias the object.
  This
can only happen in rare cases (when the object is constructed in
the scope
of the const member fn invocation, and when all the non-const mem
ber
function invocations between the object's construction and the const

member fn invocation are statically bound, and when every one of
these
invocations is also "inline"d, and when the constructor itself is
"inline"d,
and when any member fns the constructor calls are inline).


--
                            既然热爱生命
                            那么,
                            一切都在意料之中。

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.52.239]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店