<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>风牛菜籽 &#187; c++</title>
	<atom:link href="http://www.caiyanpei.com/tag/c-2/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.caiyanpei.com</link>
	<description>拖延症重症患者</description>
	<lastBuildDate>Tue, 25 Mar 2025 01:51:19 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.6.1</generator>
		<item>
		<title>C++中const用法浅析</title>
		<link>http://www.caiyanpei.com/c-const-uses/</link>
		<comments>http://www.caiyanpei.com/c-const-uses/#comments</comments>
		<pubDate>Mon, 13 Jun 2011 17:19:12 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://www.xiuchezu.com/?p=535</guid>
		<description><![CDATA[看到const 关键字，很多程序员想到的可能是const 常量，这可有点象踩到陷 &#8230; <a href="http://www.caiyanpei.com/c-const-uses/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>看到const 关键字，很多程序员想到的可能是const 常量，这可有点象踩到陷井上还不知道自己危险了。读读以下文字会使你对c++中的const有一个全面的认识。</p>
<p>const 是C++中常用的类型修饰符，有某些微妙的应用场合，如果没有搞清本源，则错误在所难免。本篇中将对const进行辨析。溯其本源，究其实质，希望能对大家理解const有所帮助，根据思维的承接关系，分为如下几个部分进行阐述。</p>
<p><span>C++中为什么会引入const</span></p>
<p>C++的提出者当初是基于什么样的目的引入（或者说保留）const关键字呢？，这是一个有趣又有益的话题，对理解const很有帮助。</p>
<p>1． 大家知道，C++有一个类型严格的编译系统，这使得C++程序的错误在编译阶段即可发现许多，从而使得出错率大为减少，因此，也成为了C++与C相比，有着突出优点的一个方面。</p>
<p>2． C中很常见的预处理指令 #define VariableName VariableValue 可以很方便地进行值替代，这种值替代至少在三个方面优点突出：</p>
<p>一是避免了意义模糊的数字出现，使得程序语义流畅清晰，如下例：<br />
#define USER_NUM_MAX 107 这样就避免了直接使用107带来的困惑。<br />
二是可以很方便地进行参数的调整与修改，如上例，当人数由107变为201时，进改动此处即可，<br />
三是提高了程序的执行效率，由于使用了预编译器进行值替代，并不需要为这些常量分配存储空间，所以执行的效率较高。<br />
鉴于以上的优点，这种预定义指令的使用在程序中随处可见。</p>
<p>3． 说到这里，大家可能会迷惑上述的1点、2点与const有什么关系呢?,好，请接着向下看来：</p>
<p>预处理语句虽然有以上的许多优点，但它有个比较致命的缺点，即，预处理语句仅仅只是简单值替代，缺乏类型的检测机制。这样预处理语句就不能享受C++严格类型检查的好处，从而可能成为引发一系列错误的隐患。</p>
<p>4．好了，第一阶段结论出来了：</p>
<p>结论： <span>Const 推出的初始目的，正是为了取代预编译指令，消除它的缺点，同时继承它的优点</span>。<br />
现在它的形式变成了：<br />
Const DataType VariableName = VariableValue ;<br />
为什么const能很好地取代预定义语句？<br />
const 到底有什么大神通，使它可以振臂一挥取代预定义语句呢？</p>
<p>1． 首先，以const 修饰的常量值，具有不可变性，这是它能取代预定义语句的基础。<br />
2． 第二，很明显，它也同样可以避免意义模糊的数字出现，同样可以很方便地进行参数的调整和修改。<br />
3． 第三，C++的编译器通常不为普通const常量分配存储空间，而是将它们保存在符号表中，这使得它成为一个编译期间的常量，没有了存储与读内存的操作，使得它的效率也很高，同时，这也是它取代预定义语句的重要基础。<br />
这里，我要提一下，为什么说这一点是也是它能取代预定义语句的基础，这是因为，编译器不会去读存储的内容，如果编译器为const分配了存储空间，它就不能够成为一个编译期间的常量了。<br />
4． 最后，const定义也像一个普通的变量定义一样，它会由编译器对它进行类型的检测，消除了预定义语句的隐患。</p>
<p><span>const 使用情况分类详析</span></p>
<p><span>1.const 用于指针的两种情况分析：</span><br />
int const *a; //a/可变，*a不可变<br />
int *const a; //a不可变，*a可变<br />
分析：<span>const 是一个左结合的类型修饰符，它与其左侧的类型修饰符合为一个类型</span></p>
<p>修饰符，所以，int const 限定 *a,不限定a。int *const 限定a,不限定*a。</p>
<p><span>2.const 限定函数的传递值参数：</span></p>
<p>void fun(const int var);</p>
<p>分析：上述写法限定参数在函数体中不可被改变。由值传递的特点可知，var在函数体中的改变不会影响到函数外部。所以，此限定与函数的使用者无关，仅与函数的编写者有关。<br />
结论：最好在函数的内部进行限定，对外部调用者屏蔽，以免引起困惑。如可改写如下：</p>
<p>void fun(int var){<br />
const int &amp; varalias = var;</p>
<p>varalias &#8230;&#8230;&#8230;</p>
<p>}</p>
<p><span>3.const 限定函数的值型返回值：</span></p>
<p>const int fun1();<br />
const myclass fun2();</p>
<p>分析:上述写法限定函数的返回值不可被更新，当函数返回内部的类型时（如fun1），已经是一个数值，当然不可被赋值更新，所以，此时const无意义，最好去掉，以免困惑。当函数返回自定义的类型时（如fun2），这个类型仍然包含可以被赋值的变量成员，所以，此时有意义。</p>
<p><span>4. 传递与返回地址</span>： 此种情况最为常见，由地址变量的特点可知，适当使用const，意义昭然。</p>
<p><span>5. const 限定类的成员函数</span>：</p>
<p>class classname {<br />
public:<br />
int fun() const;<br />
&#8230;..<br />
}</p>
<p>注意：采用此种const 后置的形式是一种规定，亦为了不引起混淆。在此函数的声明中和定义中均要使用const,因为const已经成为类型信息的一部分。</p>
<p>获得能力：可以操作常量对象。<br />
<span>失去能力：不能修改类的数据成员，不能在函数中调用其他不是const的函数。</span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/c-const-uses/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Const，Const函数，Const变量，函数后面的Const 的区别</title>
		<link>http://www.caiyanpei.com/const-learning1/</link>
		<comments>http://www.caiyanpei.com/const-learning1/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 12:24:56 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[openGL]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://www.xiuchezu.com/?p=537</guid>
		<description><![CDATA[看到const 关键字，C++程序员首先想到的可能是const 常量。这可不是良 &#8230; <a href="http://www.caiyanpei.com/const-learning1/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>看到const 关键字，C++程序员首先想到的可能是const 常量。这可不是良好的条件反射。如果只知道用const 定义常量，那么相当于把火药仅用于制作鞭炮。const 更大的魅力是它可以修饰函数的参数、返回值，甚至函数的定义体。</p>
<p>const 是constant 的缩写，“恒定不变”的意思。被const 修饰的东西都受到强制保护，可以预防意外的变动，能提高程序的健壮性。所以很多C++程序设计书籍建议：“Use const whenever you need”。</p>
<p>1.用const 修饰函数的参数</p>
<p>如果参数作输出用，不论它是什么数据类型，也不论它采用“指针传递”还是“引用传递”，都不能加const 修饰，否则该参数将失去输出功能。const 只能修饰输入参数：</p>
<p><span style="text-decoration: underline;"><strong>如果输入参数采用“指针传递”，那么加const 修饰可以防止意外地改动该指针，起到保护作用。</strong></span></p>
<p>例如StringCopy 函数：</p>
<p>void StringCopy(char *strDestination, const char *strSource);</p>
<p>其中strSource 是输入参数，strDestination 是输出参数。给strSource 加上const修饰后，<strong><span style="text-decoration: underline;">如果函数体内的语句试图改动</span></strong><strong><span style="text-decoration: underline;">strSource 的内容，编译器将指出错误。</span></strong></p>
<p>如果输入参数采用“值传递”，由于函数将自动产生临时变量用于复制该参数，该输入参数本来就无需保护，所以不要加const 修饰。</p>
<p>例如不要将函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A 为用户自定义的数据类型。</p>
<p>对于非内部数据类型的参数而言，象void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A 类型的临时对象用于复制参数a，而临时对象的构造、复制、析构过程都将消耗时间。</p>
<p><span style="text-decoration: underline;"><strong>为了提高效率，可以将函数声明改为void Func(A &amp;a)，因为“引用传递”仅借用一下参数的别名而已，不需要产生临时对象。但是函数void Func(A &amp;a) 存在一个缺点：</strong></span></p>
<p>“引用传递”有可能改变参数a，这是我们不期望的。解决这个问题很容易，加const修饰即可，因此函数最终成为void Func(const A &amp;a)。</p>
<p>以此类推，是否应将void Func(int x) 改写为void Func(const int &amp;x)，以便提高效率？完全没有必要，因为内部数据类型的参数不存在构造、析构的过程，而复制也非常快，“值传递”和“引用传递”的效率几乎相当。</p>
<p>问题是如此的缠绵，我只好将“const &amp;”修饰输入参数的用法总结一下。</p>
<p><wbr /></p>
<p>对于非内部数据类型的输入参数，应该将“值传递”的方式改为“const 引用传递”，目的是提高效率。例如将void Func(A a) 改为void Func(const A &amp;a)。</p>
<p><wbr /></p>
<p>对于内部数据类型的输入参数，不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的，又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &amp;x)。</p>
<p>2 用const 修饰函数的返回值<br />
如果给以“指针传递”方式的函数返回值加const 修饰，那么函数返回值（即指针）的内容不能被修改，<strong><span style="text-decoration: underline;">该返回值只能被赋给加const 修饰的同类型指针。例如函数<br />
</span></strong>const char * GetString(void);<br />
如下语句将出现编译错误：<br />
char *str = GetString();<br />
正确的用法是<br />
const char *str = GetString();<br />
如果函数返回值采用“值传递方式”，由于函数会把返回值复制到外部临时的存储单元中，加const 修饰没有任何价值。<br />
例如不要把函数int GetInt(void) 写成const int GetInt(void)。<br />
同理不要把函数A GetA(void) 写成const A GetA(void)，其中A 为用户自定义的数据类型。<br />
如果返回值不是内部数据类型，将函数A GetA(void) 改写为const A &amp; GetA(void)的确能提高效率。但此时千万千万要小心，一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了，否则程序会出错。<br />
函数返回值采用“引用传递”的场合并不多，这种方式一般只出现在类的赋值函数中，目的是为了实现链式表达。</p>
<p>例如：<br />
class A<br />
{<br />
A &amp; operate = (const A &amp;other); // 赋值函数<br />
};<br />
A a, b, c; // a, b, c 为A 的对象</p>
<p>a = b = c; // 正常的链式赋值<br />
(a = b) = c; // 不正常的链式赋值，但合法<br />
如果将赋值函数的返回值加const 修饰，那么该返回值的内容不允许被改动。上例中，语句 a = b = c 仍然正确，但是语句 (a = b) = c 则是非法的。<br />
3 const 成员函数<br />
任何不会修改数据成员的函数都应该声明为const 类型。如果在编写const 成员函数时，不慎修改了数据成员，或者调用了其它非const 成员函数，编译器将指出错误，这无疑会提高程序的健壮性。以下程序中，类stack 的成员函数GetCount 仅用于计数，从逻辑上讲GetCount 应当为const 函数。编译器将指出GetCount 函数中的错误。<br />
class Stack<br />
{<br />
public:<br />
void Push(int elem);<br />
int Pop(void);<br />
int GetCount(void) const; // const 成员函数<br />
private:<br />
int m_num;<br />
int m_data[100];<br />
};<br />
int Stack::GetCount(void) const<br />
{<br />
++ m_num; // 编译错误，企图修改数据成员m_num<br />
Pop(); // 编译错误，企图调用非const 函数<br />
return m_num;<br />
}<br />
const 成员函数的声明看起来怪怪的：const 关键字只能放在函数声明的尾部，大概是因为其它地方都已经被占用了。<br />
关于Const函数的几点规则：</p>
<p>a. const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.<br />
b. const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.<br />
c. const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.<br />
d. 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的</p>
<p>文章来源：http://www.cnblogs.com/Fancyboy2004/archive/2008/12/23/1360810.html</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/const-learning1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
