﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-happy everyday-随笔分类-C++</title><link>http://www.cppblog.com/smallfa/category/8802.html</link><description>ha</description><language>zh-cn</language><lastBuildDate>Tue, 09 Dec 2008 06:15:33 GMT</lastBuildDate><pubDate>Tue, 09 Dec 2008 06:15:33 GMT</pubDate><ttl>60</ttl><item><title>从Java到C++ — 对比Java与C++编程的不同</title><link>http://www.cppblog.com/smallfa/archive/2008/12/09/68932.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Tue, 09 Dec 2008 05:43:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/09/68932.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68932.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/09/68932.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68932.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68932.html</trackback:ping><description><![CDATA[<h2>1. 数据类型和变量</h2>
<p>C++ 中的变量类型与Java很相似。像Java一样，C++ 有<tt>int</tt> 和 <tt>double</tt> 类型。但是这些数字类型的取值范围是依赖于机器的。比如在16位系统上，例如运行DOS 或Windows 3.x的PC机上，<tt>int</tt> 是双字节(2-byte)的，取值范围比Java的4-byte的<tt>int</tt> 要小很多。在这些机器上，如果 int 不够用的话，你需要使用长整型long。</p>
<p>C++ 有 <tt>short</tt> 和 <tt>unsigned</tt> 类型来更有效的存储数字。（我认为所谓有效是指更高的空间利用率。） 最好是尽量避免使用这些类型除非是空间利用的有效性对你的系统真的非常重要。</p>
<p>在C++中布尔型用 <tt>bool</tt> 表示，而不像在Java中用boolean。</p>
<p>C++ 中字符串类型用 <tt>string</tt> 表示。它与Java中的 <tt>String</tt> 类型非常相似，但是，还是要逐一以下几点不同之处：</p>
<p>1. C++ 字符串存储ASCII 码字符，而不是标准码Unicode 字符</p>
<p>2. C++ 字符串是可以被修改的，而Java字符串的内容是不可修改的(immutable)。</p>
<p>3. 取子字符串的操作在 C++ 中叫做 <tt>substr</tt>，这个命令<tt>s.substr(i, n)</tt> 从字符串s中取得从位置 i 开始长度为n的子字符串。</p>
<p>4. 在C++中，你只能够将字符串与其它字符串对象相串联(concatenate)，而不能够与任意的对象相串联。</p>
<p>5. C++中可以直接使用关系操作符 <tt>==、 !=、 &lt;、 &lt;=、 &gt;、 &gt;= </tt>来进行字符串比较，其中后面四个操作符是按字母顺序进行比较的。 这比Java中使用函数equals和compareTo来比较要方便很多。</p>
<br><br>
<h2>2. 变量和常量</h2>
<p>在C++中，本地变量的定义看起来与Java中相同，例如：</p>
<p><tt>int n = 5;</tt></p>
<p>实际上这正是C++和Java的一个重要不同之处。C++编译器不对本地变量进行初始化检验，所以在C++中很容易忘记初始化一个变量，这种情况下，变量的值该变量所占内存区域中刚好当前存在随机值。这显然是很容易产生程序出错的地方。</p>
<p>与Java一样， C++中类可以有数据域和静态变量。不同的是，C++中变量可以在函数甚至是类的外面定义，这些所谓的全局变量可以在程序的任何函数中被访问，因而不易被很好的管理。所C++中应该尽量避免使用全局变量。</p>
<p>在C++中，常量可以在任何地方被定义（记得在Java中，常量必须是类的静态数据static data)。 C++ 使用关键字 <tt>const</tt> 来定义常量，而Java中是 <tt>final</tt>。例如：</p>
<p><tt>const int DAYS_PER_YEAR = 365;</tt></p>
<br><br><br>
<h2>3. 类</h2>
<p>C++ 中对类的定义与Java有些不同，这里是一个例子：一个C++ 版本的 <tt>Point</tt> 类:</p>
<p><tt>class Point /* C++ */</tt></p>
<p><tt>{</tt></p>
<p><tt>public:</tt></p>
<p><tt>Point();</tt></p>
<p><tt>Point(double xval, double yval);</tt></p>
<p><tt>void move(double dx, double dy);</tt></p>
<p><tt>double getX() const;</tt></p>
<p><tt>double getY() const;</tt></p>
<p><tt>private:</tt></p>
<p><tt>double x;</tt></p>
<p><tt>double y;</tt></p>
<p><tt>};</tt></p>
<p>这里几点重要的不同是：</p>
<p>1. C++的类定义中分为公共和私有部分，分别以关键字 <tt>public</tt> 和 <tt>private</tt>开始。而在Java中，每一个元素都必须标明 <tt>public</tt> 或 <tt>private</tt>。</p>
<p>2. C++中类的定义只包含函数的声明，真正的实现另外单独列出。</p>
<p>3. 访问函数(accessor methods)标有关键字 <tt>const</tt> ，表明这个函数不会改变本对象的元素值。</p>
<p>4. 类定义的结尾处有分号</p>
<p>类中函数的实现跟在类的定义之后。因为函数是在类外面定义的，所以每一个函数的名字前面要加类名称作为前缀，并使用操作符双冒号::来分割类的名称和函数的名称。不改变隐含参数值（即当前对象的值）的访问函数用 <tt>const</tt>标明。如下所示是上面类定义中的函数的实现：</p>
<p><tt>Point::Point() { x = 0; y = 0; }</tt></p>
<p><tt>void Point::move(double dx, double dy) </tt></p>
<p><tt>{</tt></p>
<p><tt>x = x + dx;</tt></p>
<p><tt>y = y + dy;</tt></p>
<p><tt>}</tt></p>
<p><tt>double Point::getX() const</tt></p>
<p><tt>{ </tt></p>
<p><tt>return x;</tt></p>
<p><tt>}</tt></p>
<br><br><br>
<h2>4. 对象</h2>
<p>Java 与 C++ 最主要的不同在于对象变量的使用。在 C++中，对象变量存储的是真正的对象的值，而不是对象引用(<a title=关于reference的文章 href="http://www.prglab.com/blog/p/28"><u><font color=#810081>reference</font></u></a>)。注意在C++中构造一个对象的时候是不使用关键字new的，只需要在变量的名字后面直接赋予构造函数的参数就可以了，例如：</p>
<p><tt>Point p(1, 2); /* 构造对象 p */</tt></p>
<p>如果不跟参数赋值，则使用默认构造函数，例如：</p>
<p><tt>Time now; /* 默认使用构造函数 Time::Time() */</tt></p>
<p>这一点与Java很不同。在Java中，这个命令仅仅生成一个没有初始化的reference，而在C++中，它生成一个实际的对象。</p>
<p>当一个对象被赋给另一个对象变量的时候，实际的值将被拷贝。而在Java中，拷贝一个对象变量只不过是建立了另外一个指向对象的reference。拷贝一个C++的对象就像在Java中调用clone这个函数一样，而修改拷贝的值不会改变原对象的值。例如：</p>
<p><tt>Point q = p; /* 拷贝p到q */</tt></p>
<p><tt>q.move(1, 1); /* 移动q而p不动，即q的值变了，而p的不变*/</tt></p>
<p>多数情况下，C++中这种对象直接对值操作的特性使用起来很方便，但是也有些时候不尽如人意：</p>
<p>1. 当需要一个函数中修改一个对象的值，必须记住要使用按引用调用call by reference (参见下面函数部分)</p>
<p>2. 两个对象变量不能指向同一个对象实体。如果你要在C++中实现这种效果，必须使用指针pointer（参见下面指针部分）</p>
<p>3. 一个对象变量只能存储一种特定的类型的值，如果你想要使用一个变量来存储不同子类的对象的值（多态ploymorphism)，则需要使用指针。</p>
<p>4. 如果你想在C++中使用一个变量来或者指向null或者指向一个实际的对象，则需要使用指针</p>
<br><br><br><br><br>
<h2>5. 函数</h2>
<p>在Java中，每一个函数必须或者是对象函数(instance method)，或者是静态函数(static function)或称类函数。C++同样支持对象函数和静态函数（类函数），但同时C++也允许定义不属于任何类的函数，这些函数叫做全局函数<em>（global functions）</em>。</p>
<p>特别的是，每一个C++ 程序都从一个叫做 <tt>main</tt>的全局函数开始执行：</p>
<p><tt>int main()</tt></p>
<p><tt>{ . . .</tt></p>
<p><tt>}</tt></p>
<p>还有另外一个格式的main函数可以用来捕捉命令行参数，类似于Java的main函数，但是它要求关于C格式的数组和字符串的知识，这里就不介绍了。</p>
<p>按照习惯，通常如果程序执行成功， <tt>main</tt> 函数返回0，否则返回非零整数。</p>
<p>同Java一样，函数参数是通过值传递的(passed by value)。在Java中，函数无论如何都是可以修改对象的值的。然而在C++中，因为对象直接存储的是实际的值，而不是指向值的reference，也就是说传入函数的是一个实际值的拷贝，因此也就无法修改原来对象的值。</p>
<p>所以，C++ 有两种参数传递机制，同Java一样的按值调用(<em>call by value) </em>，以及按地址调用(<em>call by reference</em>)。当一个参数是按reference传递时，函数可以修改其原始值。Call by reference 的参数前面有一个地址号 <tt>&amp;</tt> 跟在参数类型的后面，例如：</p>
<p><tt>void raiseSalary(Employee&amp; e, double by)</tt></p>
<p><tt>{ . . .</tt></p>
<p><tt>}</tt></p>
<p>下面是一个典型的利用call by reference的函数，在Java中是无法实现这样的功能的。</p>
<p><tt>void swap(int&amp; a, int&amp; b)</tt></p>
<p><tt>{ int temp = a;</tt></p>
<p><tt>a = b;</tt></p>
<p><tt>b = temp;</tt></p>
<p><tt>}</tt></p>
<p>如果使用 <tt>swap(x, y)</tt>来调用这个函数，则reference参数 <tt>a</tt> 和 <tt>b</tt> 指向原实际参数<tt>x</tt> 和 <tt>y</tt>的位置，而不是它们的值的拷贝，因此这个函数可以实现实际交换这两个参数的值。</p>
<p>在 C++中，每当需要实现修改原参数的值时你就可以使用按地址调用 call by reference </p>
<br><br><br>
<h2>6. 向量Vector</h2>
<p>C++ 的向量结构结合了Java中数组和向量两者的优点。一个C++ 的向量可以方便的被访问，其容量又可以动态的增长。如果 <tt>T</tt> 是任意类型，则 <tt>vector&lt;T&gt;</tt> 是一个元素为 <tt>T</tt> 类型的动态数组。下面的语句</p>
<p><tt>vector&lt;int&gt; a;</tt></p>
<p>产生一个初始为空的向量。而语句</p>
<p><tt>vector&lt;int&gt; a(100);</tt></p>
<p>生成一个初始有100个元素的向量。你可以使用<tt>push_back</tt> 函数来添加元素：</p>
<p><tt>a.push_back(n);</tt></p>
<p>调用 <tt>a.pop_back()</tt> 从<tt>a</tt>中取出最后一个元素（操作后这个元素被从a中删掉)， 使用函数<tt>size</tt> 可以得到当前a中的元素个数。</p>
<p>你还可以通过我们熟悉的 <tt>[]</tt> 操作符来访问向量中元素，例如：</p>
<p><tt>for (i = 0; i &lt; a.size(); i++) {<br></tt></p>
<p><tt>sum = sum + a[i];</tt></p>
<p><tt>}</tt></p>
<p>同Java中一样，数组索引必须为 0 和 <tt>a.size() - 1</tt>之间的值。但是与Java不同的是，C++中没有runtime的索引号合法性检验。试图访问非法的索引位置可能造成非常严重的出错。</p>
<p>就像所有其它 C++ 对象一样，向量也是值。如果你将一个向量赋值给另外一个向量变量，所有的元素都会被拷贝过去。</p>
<p><tt>vector&lt;int&gt; b = a; /* 所有的元素都被拷贝了 */</tt></p>
<p>对比Java中的情况，在Java中，一个数组变量是一个指向数组的reference。拷贝这个变量仅仅产生另外一个指向同一数组的reference，而不会拷贝每一个元素的值。</p>
<p>正因如此，如果一个C++函数要实现修改向量的值，必须使用reference参数：</p>
<p><tt>void sort(vector&lt;int&gt;&amp; a)</tt></p>
<p><tt>{ . . .</tt></p>
<p><tt>}</tt></p>
<br><br><br>
<h2>7. 输入和输出</h2>
<p>在C++中，标准的输入输出流用对象 <tt>cin</tt> 和 <tt>cout</tt> 表示。我们使用 <tt>&lt;&lt;</tt> 操作符写输出，例如：</p>
<p><tt>cout &lt;&lt; &#8220;Hello, World!&#8221;;</tt></p>
<p>也可以连着输出多项内容，例如：</p>
<p><tt>cout &lt;&lt; &#8220;The answer is &#8221; &lt;&lt; x &lt;&lt; &#8220;\n&#8221;;</tt></p>
<p>我们使用 <tt>&gt;&gt;</tt> 操作符来读入一个数字或单词，例如：</p>
<p><tt>double x;</tt></p>
<p><tt>cout &lt;&lt; &#8220;Please enter x: &#8220;;</tt></p>
<p><tt>cin &gt;&gt; x;</tt></p>
<p><tt>string fname;</tt></p>
<p><tt>cout &lt;&lt; &#8220;Please enter your first name: &#8220;;</tt></p>
<p><tt>cin &gt;&gt; fname;</tt></p>
<p>函数<tt>getline</tt> 可以读入整行的输入，例如：</p>
<p><tt>string inputLine;</tt></p>
<p><tt>getline(cin, inputLine);</tt></p>
<p>如果到达输入的结尾，或者一个数字无法被正确的读入，这个流对象会被设置为 failed 状态，我们可以使用函数 <tt>fail</tt> 来检验这个状态，例如：</p>
<p><tt>int n;</tt></p>
<p><tt>cin &gt;&gt; n;</tt></p>
<p><tt>if (cin.fail()) cout &lt;&lt; &#8220;Bad input&#8221;;</tt></p>
<p>一旦一个流的状态被设为failed，我们是很难重置它的状态的，所以如果你的程序需要处理错误输入的情况，应该使用函数 <tt>getline</tt> 然后人工处理得到的输入数据。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<br><br>
<h2>8. 指针pointer</h2>
<p>我们已经知道在C++中，对象变量直接存储的是对象的值。这是与Java不同的，在Java中对象变量存储的是一个地址，该地址指向对象值实际存储的地方。有时在C++中也需要实现这样的布置，这就用到了指针pointer。在 C++中，一个指向对象的变量叫做指针。如果T是一种数据类型，则 <tt>T*</tt> 是指向这种数据类型的指针。</p>
<p>就像 Java中一样，一个指针变量可以被初始化为空值 <tt>NULL</tt>，另外一个指针变量的值，或者一个调用new生成的新对象：</p>
<p><tt>Employee* p = NULL;</tt></p>
<p><tt>Employee* q = new Employee(&#8221;Hacker, Harry&#8221;, 35000);</tt></p>
<p><tt>Employee* r = q;</tt></p>
<p>实际上在C++中还有第四种可能，那就是指针可以被初始化为另外一个对象的地址，这需要使用地址操作符 <tt>&amp;</tt> ：</p>
<p><tt>Employee boss(&#8221;Morris, Melinda&#8221;, 83000);</tt></p>
<p><tt>Employee* s = &amp;boss;</tt></p>
<p>这实际上并不是什么好主意。保险的做法还是应该直接让指针指向使用 <tt>new</tt>生成的新对象。</p>
<p>到目前为止，C++ 指针看起来非常像 Java 的对象变量。然而，这里有一个很重要的语法的不同。我们必须使用星号操作符 <tt>*</tt> 来访问指针指向的对象。如果 <tt>p</tt> 是一个指向<tt>Employee</tt>对象的指针，则 <tt>*p</tt> 才代表了这个对象：</p>
<p><tt>Employee* p = . . .;</tt></p>
<p><tt>Employee boss = <strong>*p</strong>;</tt></p>
<p>当我们需要执行对象的函数或访问对象的一个数据域时，也需要使用 <tt>*p</tt> ：</p>
<p><tt>(*p).setSalary(91000);</tt></p>
<p>*p外面的括号是必需的，因为 <tt>.</tt> 操作符比 * 操作符有更高的优先级。C的设计者觉得这种写法很难看，所以他们提供了另外一种替代的写法，使用 -&gt; 操作符来实现 <tt>*</tt> 和 <tt>.</tt> 操作符的组合功能。表达式</p>
<p><tt>p-&gt;setSalary(91000);</tt></p>
<p>可以调用对象*p的函数 <tt>setSalary</tt> 。你可以简单的记住 <tt>.</tt> 操作符是在对象上使用的，-&gt; 操作符是在指针上使用的。</p>
<p>如果你不初始化一个指针，或者如果一个指针为空值 NULL 或指向的对象不再存在，则在它上面使用 <tt>*</tt> 或 <tt>-&gt;</tt> 操作符就会出错。 不幸的是 C++ runtime 系统并不检查这个出错。如果你范了这个错误，你的程序可能会行为古怪或死机。</p>
<p>而在Java中，这些错误是不会发生的。所有的reference都必须初始化，所有的对象只要仍有reference指向它就不会被从内存中清除，因此你也不会有一个指向已被删除的对象的reference。Java的runtime 系统会检查reference是否为空，并在遇到空指针时抛出一个null pointer的例外(exception)。</p>
<p>C++ 和 Java还有一个显著的不同，就是 Java 有<em>垃圾回收</em>功能，能够自动回收被废弃的对象。而在C++中，需要程序员自己管理内存分配回收。</p>
<p>C++中当对象变量超出范围时可以自动被回收。但是使用new生成的对象必须用delete操作符手动删除，例如：</p>
<p><tt>Employee* p = new Employee(&#8221;Hacker, Harry&#8221;, 38000);</tt></p>
<p><tt>. . .</tt></p>
<p><tt>delete p; /* 不在需要这个对象 */</tt></p>
<p>如果你忘记删除一个对象，那么你的程序有可能最终用光所有内存。这就是我们常说的内存泄漏 (<em>memory leak</em>)。更重要的是，如果你如果删除了一个对象，然后又继续使用它，你可能覆盖不属于你的数据。如果你刚巧覆盖了用于处理内存回收的数据域，那么内存分配机制就可能运转失常而造成更严重的错误，而且很难诊断和修复。因此，在C++中最好尽量少用指针</p>
<br><br><br>
<h2>9. 继承</h2>
<p>C++和Java中继承的基本语法是很相似的。在C++中，使用 <tt>: public</tt> 代替Java中的<tt>extends</tt> 来表示继承关系 。 (C++ 也支持私有继承的概念，但是不太有用。)</p>
<p>默认情况下，C++中的函数不是动态绑定的。如果你需要某个函数实现动态绑定，需要使用<tt>virtual</tt>声明它为虚函数，例如：</p>
<p><tt>class Manager : public Employee</tt></p>
<p><tt>{ </tt></p>
<p><tt>public:</tt></p>
<p><tt>Manager(string name, double salary, string dept);</tt></p>
<p><tt><strong>virtual</strong> void print() const;</tt></p>
<p><tt>private:</tt></p>
<p><tt>string department;</tt></p>
<p><tt>};</tt></p>
<p>同Java一样，构造函数中调用父类的构造函数有特殊的语法。 Java使用关键字 <tt>super</tt>。C++中必须在子类的构造函数体外调用父类的构造函数。下面是一个例子：</p>
<p><tt>Manager::Manager(string name, double salary, string dept)</tt></p>
<p><tt><strong>: Employee(name, salary) </strong>/* 调用父类的构造函数 */</tt></p>
<p><tt>{ department = dept;</tt></p>
<p><tt>}</tt></p>
<p>Java 中在子类函数中调用父类的函数时也使用关键字 <tt>super</tt> 。而在C++中是使用父类的名称加上操作符 <tt>::</tt>表示，例如：</p>
<p><tt>void Manager::print() const</tt></p>
<p><tt>{ <strong>Employee::print(); </strong>/* 调用父类的函数 */</tt></p>
<p><tt>cout &lt;&lt; department &lt;&lt; &#8220;\n&#8221;;</tt></p>
<p><tt>}</tt></p>
<p>一个 C++ 对象变量只能存储特定类型的对象值。要想在C++中实现多态(polymorphism)，必须使用指针。一个 <tt>T*</tt> 指针可以指向类型为 <tt>T</tt> 或 <tt>T</tt> 的任意子类的对象，例如：</p>
<p><tt>Employee* e = new Manager(&#8221;Morris, Melinda&#8221;, 83000, &#8220;Finance&#8221;);</tt></p>
<p>你可以将父类和不同子类的对象混合收集到一个元素均为指针的向量中，然后调用动态绑定的函数，如下所示：</p>
<p><tt>vector&lt;Employee*&gt; staff;</tt></p>
<p><tt>. . .</tt></p>
<p><tt>for (i = 0; i &lt; staff.size(); i++)</tt></p>
<p><tt>staff[i]-&gt;print();</tt></p>
<img src ="http://www.cppblog.com/smallfa/aggbug/68932.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-09 13:43 <a href="http://www.cppblog.com/smallfa/archive/2008/12/09/68932.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正确的方法是定义operator++以reference为参数类型  C++中Reference与指针（Pointer）的使用对比</title><link>http://www.cppblog.com/smallfa/archive/2008/12/09/68928.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Tue, 09 Dec 2008 05:16:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/09/68928.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68928.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/09/68928.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68928.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68928.html</trackback:ping><description><![CDATA[<p>day &amp;operator++(day &amp;d)<br>{<br>d = (day)(d + 1);<br>return d;<br>}</p>
<p>使用这个函数， 表达式 ++x 才有正确的显示以及正确的操作。<br>Passing by reference不仅仅是写operator++较好的方法，而是唯一的方法。<br><br><br>&nbsp;C++在这里并没有给我们选择的余地。<br>&nbsp;像下面的声明:<br>day *operator++(day *d);<br>是不能 通过编译的。<br>每个重载的操作符函数必须或者是一个类的成员， 或者使用类型T、 T &amp; 或 T const &amp; 为参数类型，<br>这里T是一个类(class)或列举(enumeration)类型。 <br><br>也就是说，每一个重载操作符必须以类或列举类型为参数类型。<br><br>指针，即使是指向一个类或列举类型对象的指针，也不可以用。<br><br>C++ 不允许在重载操作符时重新定义内置操作符的含义，包括指针类型。<br>因此，我们不可以定义：<br>int operator++(int i); // 错误<br>因为它试图对int重新定义操作符 ++ 的含义。 我们也不可以定义：<br>int *operator++(int *i); // 错误<br>因为它试图对 int * 重新定义操作符 ++ 的含义<br><br></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2>References vs. const pointers</h2>
<p>C++ 中不允许定义&#8221;const reference&#8221;，<br>&nbsp;因为一个reference天生就是const。也就是说，一旦将一个reference绑定到一个对象，就无法再将它重新绑定到另一个不同的对象。<br>在声 明一个reference之后没有写法可以将它重新绑定到另外一个对象。<br>例如：<br>int &amp;ri = i;<br>将 ri 绑定到 i 。然后下面的赋值:<br>ri = j;<br>并不是把 ri 绑定到 j ，而是将 j 中的值赋给 ri 指向的对象，也就是赋给 i 。<br><br><br><br></p>
<p>简而言之，<br>一个pointer在它的有生之年可以指向许多不同的对象，<br>而一个reference只能够指向一个对象。<br>有些人认为这才是 reference和 pointer最大的不同。<br>我并不赞成。也许这是reference与pointer的一点不同， 但并不是reference和const pointer的不同。<br>在强调一遍，一旦一个reference与一个对象绑定，就不能再将它改指向另外的东西。<br>既然不能再绑定reference之后再 改变， 一个reference就必须在一出生就被绑定。<br>否则这个reference就永远不能被绑定到任何东西，也就毫无用处了。</p>
<p>上一段的讨论也同样完全适用于常量指针（const pointer）。<br>（注意，我这里说的是常量指针（const pointer）， 而不是指向常量的指针 &#8220;pointers to const&#8221;。)<br>&nbsp;例如，<br>一个reference声明必须同时带有一个初始化赋值，如下所示：</p>
<blockquote>
<p style="BACKGROUND-COLOR: #00ff00">void f()<br>{<br>int &amp;r = i;<br>&#8230;<br>}</p>
</blockquote>
<p>省略这个初始化赋值将产生一个编译错误：</p>
<blockquote>
<p style="BACKGROUND-COLOR: #00ff00">void f()<br>{<br>int &amp;r; //错误<br>&#8230;<br>}</p>
</blockquote>
<p>一个常量指针的声明也同样必须带有一个初始化赋值，如下所示：</p>
<blockquote>
<p style="BACKGROUND-COLOR: #00ff00">void f()<br>{<br>int *const p = &amp;i;<br>&#8230;<br>}</p>
</blockquote>
<p>省略这个初始化赋值同样会出错：</p>
<blockquote>
<p style="BACKGROUND-COLOR: #00ff00"><span style="BACKGROUND-COLOR: #00ff00">void f(){<br>int *const p; // 错误<br>&#8230;<br>}</span></p>
</blockquote>
<p>在我看来 <br>不能够对reference二次绑定作为reference与pointer的不同。<br>并不比常量指针和非常量指针的不同更为显著。<br><br><br><br><br></p>
<h2>Null references</h2>
<p>除了显示的不同，常量指针与reference还有一点非常不同，那就是，一个有效的reference必须指向一个对象；而一个指针不需要。一个指针，即使是一个常量指针， 都可以有空值。 一个空指针不指向任何东西。</p>
<p>这点不同就暗示当你想要确信一个参数必须指向一个对象的时候，应该使用reference作为参数类型。 例如，交换函数(swap function)，它接受两个int参数，并将两个参数的数值对调，如下所示：</p>
<blockquote>
<p>int i, j;<br>swap(i, j);</p>
</blockquote>
<p>将原本在 i 中的值放到 j 中， 并将原本在 j 中的值放到 i 中。我们可以这样写这个函数：</p>
<blockquote>
<p>void swap(int *v1, int *v2)<br>{<br>int temp = *v1;<br>*v1 = *v2;<br>*v2 = temp;<br>}</p>
</blockquote>
<p>这种定义下，函数要像这样被调用: <strong>swap(&amp;i, &amp;j);</strong></p>
<p>这个接口暗示其中一个或两个参数都有可能为空(null)。而这个暗示是误导的。例如，调用<strong><br>swap(&amp;i, NULL);<br></strong>的后果很可能是不愉快的。</p>
<p>而像下面这样定义reference为参数：</p>
<blockquote>
<p>void swap(int &amp;v1, int &amp;v2)<br>{<br>int temp = v1;<br>v1 = v2;<br>v2 = temp;<br>}</p>
</blockquote>
<p>清晰的表明了调用swap应该提供两个对象，它们的值将被交换。 并且这样定义的另一个好处是，在调用这个函数的时候，不需要使用那些&amp;符号，看起来更顺眼：<br><strong>swap(i, j);</strong></p>
<p><br><br><br><br><br><br><br>&nbsp;</p>
<h2>Null references</h2>
<p>除了显示的不同，<br>常量指针与reference还有一点非常不同，<br>那就是，<span style="COLOR: red">一个有效的reference必须指向一个对象；</span><br><br>而<span style="COLOR: red">一个指针不需要</span>。<br>一个指针，即使是一个常量指针， 都可以有空值。 一个空指针不指向任何东西。<br><br></p>
<p><span style="COLOR: red">这点不同就暗示当你想要确信一个参数必须指向一个对象的时候，应该使用reference作为参数类型。</span><br>&nbsp;例如，<br>交换函数(swap function)，它接受两个int参数，并将两个参数的数值对调，如下所示：</p>
<blockquote>
<p>int i, j;<br>swap(i, j);</p>
</blockquote>
<p>将原本在 i 中的值放到 j 中， 并将原本在 j 中的值放到 i 中。我们可以这样写这个函数：</p>
<blockquote>
<p>void swap(int *v1, int *v2)<br>{<br>int temp = *v1;<br>*v1 = *v2;<br>*v2 = temp;<br>}</p>
</blockquote>
<p>这种定义下，函数要像这样被调用: <strong>swap(&amp;i, &amp;j);</strong></p>
<p>这个接口暗示其中一个或两个参数都有可能为空(null)。而这个暗示是误导的。例如，调用<strong><br>swap(&amp;i, NULL);<br></strong>的后果很可能是不愉快的。</p>
<p>而像下面这样定义reference为参数：</p>
<blockquote>
<p>void swap(int &amp;v1, int &amp;v2)<br>{<br>int temp = v1;<br>v1 = v2;<br>v2 = temp;<br>}</p>
</blockquote>
<p>清晰的表明了调用swap应该提供两个对象，它们的值将被交换。 并且这样定义的另一个好处是，在调用这个函数的时候，不需要使用那些&amp;符号，看起来更顺眼：<br><strong>swap(i, j);<br><br><br></strong></p>
<h2><span style="BACKGROUND-COLOR: #00ff00">更安全?</span></h2>
<p><br>有些人认为既然reference不能够为空，那么它应该比指针更安全。<br>&nbsp;我认为reference可能要安全一点，但不会安全很多。<br>虽然一个有效的reference不能为空，但是无效的可以呀。<br><span style="COLOR: red">实际上，在很多情况下程序有可 能产生无效的reference，而不只是空的reference。</span><br><br><span style="COLOR: red">&nbsp;例如，</span><br>你可以定义一个reference，使它绑定到一个指针指向的对象，如下所示：</p>
<blockquote>
<p style="BACKGROUND-COLOR: #00ff00">int *p;<br>&#8230;<br>int &amp;r = *p;</p>
</blockquote>
<p>如果指针*p在reference定义时刚好为空，则这个reference为空。<br>&nbsp;从技术上来说，这个错误并不在于将reference绑定到一个空值，而是在于对一个空指针去参考。<br>&nbsp;对一个空指针去参考产生了一个不确定的操作，也就意味着很多事都可能发生，而且大部分都不是什么好事。很有可能当程序将reference r 绑定到*p (p所指向的对象)的时候，p实际上没有被去参考，甚至程序只是将p的值拷贝给实现r的指针。<br>而程序将会继续执行下去直到错误在后面的运行中更为明显的表 现出来，产生不可预知的危害。</p>
<p>下面的函数<br>展示了<br>另外一种产生无效reference的方法：</p>
<blockquote>
<p style="BACKGROUND-COLOR: #00ff00">int &amp;f()<br>{<br>int i;<br>&#8230;<br>return i;<br>}</p>
</blockquote>
<p>这个函数返回一个指向本地变量 i 的reference。<br>然而当函数返回时，本地变量 i 的存储空间也就消失了。因此这个函数实际返回了一个指向被回收了的空间的reference。这个操作与返回一个指向本地变量的指针的后果相同。<br>有些编译 器可以在编译时发现这个错误，但也很有可能不会发现。<br><br><br><br></p>
<p><br><span style="COLOR: red">我喜欢reference，也有很好的理由使用它们代替pointer。<br><br>但如果你期望使用reference来使你的程序健壮性显著增强，那么你多半会失望的<br><br><br><br></p>
<h2>参考资料：</h2>
<ol>
    <li>Saks, Dan. &#8220;<a href="http://www.embedded.com/story/OEG20010221S0094" modo="false"><font color=#003366>Introduction to References</font></a>,&#8221; <em>Embedded Systems Programming,</em> January 2001, p. 81.
    <li>Saks, Dan. &#8220;<a href="http://www.embedded.com/story/OEG20010222S0050" modo="false"><font color=#003366>References and const</font></a>&#8220;, <em>Embedded Systems Programming</em> February 2001, p. 73. </li>
</ol>
</span>
<img src ="http://www.cppblog.com/smallfa/aggbug/68928.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-09 13:16 <a href="http://www.cppblog.com/smallfa/archive/2008/12/09/68928.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC6.0中重载操作符函数无法访问类的私有成员</title><link>http://www.cppblog.com/smallfa/archive/2008/12/08/68892.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Mon, 08 Dec 2008 15:50:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/08/68892.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68892.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/08/68892.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68892.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68892.html</trackback:ping><description><![CDATA[<p>在 C++ 中，操作符(运算符）可以被重载以改写其实际操作。<br>同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成员，<br>这个定义通常在头文件中完成。</p>
<p>在Visual C++中定义一般的函数为朋友函数通常是没有问题的。<br>然而对某些重载操作符的函数，<br>即使我们将它们定义为类的朋友函数，VC的编译器仍然会显示出错信息，<br>认为这些朋友函数无权访问类的私有成员。<br>我认为这应该是VC6.0的bug。<br><br></p>
<p>以下代码就是个例子:</p>
<table border=0>
    <tbody>
        <tr>
            <td>
            <pre>// 头文件 &#8220;Sample.h&#8221;
            #include&lt;iostream&gt;
            using namespace std;
            class Sample {
            public:
            Sample();
            friend ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s);
            friend istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s);
            private:
            int x;
            };</pre>
            </td>
        </tr>
    </tbody>
</table>
<pre></pre>
<table height=100 width=464 border=0>
    <tbody>
        <tr>
            <td>
            <pre>// 实现文件 &#8220;Sample.cpp&#8221;
            #include &#8220;Sample.h&#8221;
            Sample::Sample() {
            x=0;
            }
            istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s) {
            cout&lt;&lt;&#8221;Please enter a value&#8221;&lt;&lt;endl;
            in &gt;&gt; s.x ;
            return in;
            }
            ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s) {
            cout &lt;&lt; s.x &lt;&lt; endl;
            return out;
            }</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>以上代码在gnuc++中编译运行毫无问题。但是在VC++6.0中编译的时候就会出现以下的编译错误：</p>
<table border=0>
    <tbody>
        <tr>
            <td style="COLOR: #ff0000; BACKGROUND-COLOR: #00ff00">Compiling&#8230;<br>Sample.cpp<br>c:\temp\sample.cpp(8) : error C2248: &#8216;x&#8217; : cannot access private member declared in class &#8216;Sample&#8217;<br>c:\temp\sample.h(19) : see declaration of &#8216;x&#8217;<br>c:\temp\sample.cpp(13) : error C2248: &#8216;x&#8217; : cannot access private member declared in class &#8216;Sample&#8217;<br>c:\temp\sample.h(19) : see declaration of &#8216;x&#8217;<br>Error executing cl.exe.Sample.obj - 2 error(s), 0 warning(s)</td>
        </tr>
    </tbody>
</table>
<p>在VC++ 6.0中解决这个问题有以下几种方法：</p>
<ul type=1>
    <li>在头文件中实现作为朋友函数的操作符函数的重载，也就是说在实现文件&#8221;Sample.cpp&#8221;中将函数重载的实现去掉，而将头文件修改如下：<br>
    <table border=0>
        <tbody>
            <tr>
                <td>
                <pre style="BACKGROUND-COLOR: #00ff00">// 修改后的头文件 1 &#8220;Sample.h&#8221;
                #include&lt;iostream&gt;
                using namespace std;
                class Sample {
                public:
                Sample();
                friend ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s);
                <span style="BACKGROUND-COLOR: #ff0000">friend ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s) {
                cout &lt;&lt; s.x &lt;&lt; endl;
                return out;
                }</span>
                friend istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s);
                <span style="BACKGROUND-COLOR: #ff0000">friend istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s) {
                cout&lt;&lt;&#8221;Please enter a value&#8221;&lt;&lt;endl;
                in &gt;&gt; s.x ;
                return in;
                }</span>
                private:
                int x;
                };</pre>
                </td>
            </tr>
        </tbody>
    </table>
    <pre></pre>
    <li>在头文件中类定义之前将类和朋友操作符函数的原型特别声明一下，也就是将头文件修改如下(实现文件&#8221;Sample.cpp&#8221;不用作任何修改)：<br>
    <table border=0>
        <tbody>
            <tr>
                <td>
                <pre>// 修改后的头文件 2 &#8220;Sample.h&#8221;
                #include&lt;iostream&gt;
                using namespace std;
                // 以下3行代码为新加入
                <span style="BACKGROUND-COLOR: #ff0000">class Sample;
                ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s);
                istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s);</span>
                class Sample {
                public:
                Sample();
                friend ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s);
                friend istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s);
                private:
                int x;
                };</pre>
                </td>
            </tr>
        </tbody>
    </table>
    <pre></pre>
    <li>第三种方法是对I/O名空间的使用实行明确声明，也就是说在头文件&#8221;Sample.h&#8221;中直接写：<br>#include&lt;iostream&gt;<br>using std::ostream;<br>using std::istream<br>&#8230;.<br>取代 &#8220;using namespace std;&#8221;<br>注意：在这个例子里我们在实现文件 &#8220;Sample.cpp&#8221;中包含 &#8220;using namespace std;&#8221;这句话，否则在实现中就不能使用 &#8220;cout&#8221; , &#8220;cin&#8221;, &#8220;&lt;&lt; &#8220;, &#8220;&gt;&gt;&#8221; 和 endl 这些关键字和符号。修改后的完整代码如下：
    <p>&#160;</p>
    <table border=0>
        <tbody>
            <tr>
                <td>
                <pre>// Sample.h
                #include&lt;iostream&gt;
                <span style="BACKGROUND-COLOR: #ff0000">using std::istream;
                using std::ostream;</span>
                class Sample {
                public:
                Sample();
                friend ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s);
                /*friend ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s) {
                cout &lt;&lt; s.x &lt;&lt; endl;
                return out;
                }*/
                friend istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s);
                /*friend istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s) {
                cout&lt;&lt;&#8221;Please enter a value&#8221;&lt;&lt;endl;
                in &gt;&gt; s.x ;
                return in;
                }*/
                private:
                int x;
                };</pre>
                </td>
            </tr>
        </tbody>
    </table>
    <table height=265 width=486 border=0>
        <tbody>
            <tr>
                <td>
                <pre>// &#8220;Sample.cpp&#8221;
                #include &#8220;Sample.h&#8221;
                using namespace std;
                Sample::Sample() {
                x=5;
                }
                istream &amp;operator&gt;&gt;(istream &amp;in, Sample &amp; s) {
                cout&lt;&lt;&#8221;Please enter a value&#8221;&lt;&lt;endl;
                in &gt;&gt; s.x ;
                return in;
                }
                ostream &amp;operator&lt;&lt;(ostream &amp;out, const Sample s) {
                cout &lt;&lt; s.x &lt;&lt; endl;
                return out;
                }</pre>
                </td>
            </tr>
        </tbody>
    </table>
    <pre></pre>
    </li>
</ul>
<!-- You can start editing here. -->
<img src ="http://www.cppblog.com/smallfa/aggbug/68892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-08 23:50 <a href="http://www.cppblog.com/smallfa/archive/2008/12/08/68892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类型转换高级 (Advacned Class Type-casting)</title><link>http://www.cppblog.com/smallfa/archive/2008/12/08/68836.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Mon, 08 Dec 2008 04:58:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/08/68836.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68836.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/08/68836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68836.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68836.html</trackback:ping><description><![CDATA[<h3>reinterpret_cast</h3>
<p>reinterpret_cast 可以将一个指针转换为<span style="COLOR: red">任意其它类型的指针</span>。<br>它也可以用来将一个指针转换为一个整型，或反之亦然。</p>
<p>这个操作符可以在<span style="COLOR: red">互不相关的类</span>之间进行指针转换，<br>操作的结果是简单的将一个指针的二进制数据(binary copy)复制到另一个指针。<br>对指针指向的内容不做任何检查或转换。<br></p>
<p>例如：</p>
<div class=program>class A {};<br>class B {};<br>A * a = new A;<br>B * b = reinterpret_cast&lt;B*&gt;(a); </div>
<p>reinterpret_cast 对所有指针的处理与传统的类型转换符所作的一模一样。<br><br>_________________________________________________________________<br></p>
<h3>static_cast</h3>
<p>static_cast 可以执行所有能够隐含执行的类型转换，以及它们的反向操作（即使这种方向操作是不允许隐含执行的）。</p>
<p>用于类的指针，也就是说，它允许将一个引申类的指针转换为其基类类型（这是可以被隐含执行的有效转换），同时也允许进行相反的转换：将一个基类转换为一个引申类类型。</p>
<p>在后面一种情况中，<span style="COLOR: red">不会检查被转换的基类是否真正完全是目标类型的</span>。例如下面的代码是合法的：</p>
<div class=program>class Base {};<br>class Derived: public Base {};<br>Base * a = new Base;<br>Derived * b = static_cast<derived>(a); </derived></div>
<p>static_cast除了能够对类指针进行操作，还可以被用来进行类中明确定义的转换，以及对基本类型的标准转换：</p>
<p><code>double d=3.14159265;<br>int i = static_cast&lt;int&gt;(d); </code></p>
<div class=note>
<p>译者注：如果你对这部分看不太懂，请结合下面的dynamic_cast一起看，也许会帮助理解。</p>
</div>
<p><br><br><br><br><br><br><br><br><br><br></p>
<h3>dynamic_cast</h3>
<p>dynamic_cast 完全被用来进行指针的操作。它可以用来进行任何可以隐含进行的转换操作以及它们被用于多态类情况下的方向操作。<br><br><span style="COLOR: red">然而与static_cast不同的是，<br>&nbsp;dynamic_cast 会检查后一种情况的操作是否合法，<br>也就是说它会检查类型转换操作是否会返回一个被要求类型的有效的完整的对象。</span></p>
<p>这种检查是在程序运行过程中进行的。如果被转换的指针所指向的对象不是一个被要求类型的有效完整的对象，返回值将会是一个空指针NULL 。</p>
<div class=program>
<pre>   class Base { virtual dummy(){}; };<br>   class Derived : public Base { };<br>   <br><br>   Base* b1 = new Derived;<br>   Base* b2 = new Base;<br>   Derived* d1 = dynamic_cast<derived>(b1);   <font class=codecomment color=#008000>// succeeds</font>
Derived* d2 = dynamic_cast<derived>(b2);   <font class=codecomment color=#008000>// fails: returns NULL</font>
</derived></derived></pre>
</div>
<p>如果类型转换被用在引用(reference)类型上，而这个转换不可能进行的话，一个bad_cast 类型的例外(exception)将会被抛出：</p>
<div class=program>
<pre>  class Base { virtual dummy(){}; };<br>  class Derived : public Base { };<br>  <br>  Base* b1 = new Derived;<br>  Base* b2 = new Base;<br>  Derived d1 = dynamic_cast<derived>(b1);   <font class=codecomment color=#008000>// succeeds</font>
Derived d2 = dynamic_cast<derived>(b2);   <font class=codecomment color=#008000>// fails: exception thrown</font>
</derived></derived></pre>
</div>
<p><br><br><br><br><br><br><br></p>
<h3>const_cast</h3>
<p>这种类型转换对常量const 进行设置或取消操作：</p>
<div class=program>class C {};<br>const C * a = new C;<br>C * b = const_cast&lt;C*&gt; (a); </div>
<p>其他3种cast 操作符都不可以修改一个对象的常量属性(constness)。</p>
<p><br><br><br></p>
<h3>typeid</h3>
<p>ANSI-C++ 还定义了一个新的操作符叫做 typeid ，<br>它检查一个表达式的类型：</p>
<p><code>typeid (expression)</code> </p>
<p>这个操作符返回一个类型为type_info的常量对象指针，这种类型定义在标准头函数<typeinfo>中。这种返回值可以用操作符 == 和 != 来互相进行比较，<br>也可以用来通过name()函数获得一个描述数据类型或类名称的字符串，<br><br>例如：</typeinfo></p>
<p>
<table class=example cellSpacing=1 cellPadding=10 border=0>
    <tbody>
        <tr>
            <td class=program>
            <pre>    <font class=codecomment color=#008000>// typeid, typeinfo</font>
            #include &lt;iostream.h&gt;
            #include &lt;typeinfo&gt;
            class CDummy { };
            int main () {
            CDummy* a,b;
            if (typeid(a) != typeid(b)) {
            cout &lt;&lt; "a and b are of different types:\n";
            cout &lt;&lt; "a is: " &lt;&lt; typeid(a).name() &lt;&lt; '\n';
            cout &lt;&lt; "b is: " &lt;&lt; typeid(b).name() &lt;&lt; '\n';
            }
            return 0;
            }
            </pre>
            </td>
            <td class=console vAlign=top width=250>a and b are of different types:<br>a is: class CDummy *<br>b is: class CDummy</td>
        </tr>
    </tbody>
</table>
<br><br></p>
<img src ="http://www.cppblog.com/smallfa/aggbug/68836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-08 12:58 <a href="http://www.cppblog.com/smallfa/archive/2008/12/08/68836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>名空间 (Namespaces)</title><link>http://www.cppblog.com/smallfa/archive/2008/12/08/68833.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Mon, 08 Dec 2008 04:33:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/08/68833.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68833.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/08/68833.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68833.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68833.html</trackback:ping><description><![CDATA[<h3>标准名空间(Namespace std)</h3>
<p><br>&nbsp;</p>
<p>我们能够找到的关于名空间的最好的例子就是标准C++ 函数库本身。<br><br>如ANSI C++ 标准定义，<br>标准C++库中的所有类、对象和函数都是定义在名空间std下面的。<br><br></p>
<p>你可能已经注意到，我们在这个教程中全部忽略了这一点。作者决定这么做是因为这条规则几乎和ANSI 标准本身一样年轻 (1997) ，许多老一点的编译器并不兼容这条规则。<br><br></p>
<p>几乎所有的编译器，即使是那些与ANSI 标准兼容的编译器，都允许使用传统的头文件 (如iostream.h, stdlib.h, 等等)，就像我们在这个教程中所使用的一样。<br><br><br>然而，ANSI标准完全重新设计了这些函数库，<br>利用了模板功能，<br>而且遵循了这条规则将所有的函数和变量定义在了名空间std下。<br><br></p>
<p>该标准为这些头文件定义了新的名字，对针对C++的文件基本上是使用同样的名字，但没有.h的扩展名，<br><br>例如, iostream.h 变成了iostream。</p>
<p>如果我们使用ANSI-C++ 兼容的包含文件，我们必须记住所有的函数、类和对象是定义在名空间 std 下面的，例如：</p>
<p>
<table class=example cellSpacing=1 cellPadding=10 border=0>
    <tbody>
        <tr>
            <td class=program>
            <pre>    <font class=codecomment color=#008000>// ANSI-C++ compliant hello world</font>
            <font color=#ff0000>#include &lt;iostream&gt;</font>
            int main () {
            <font color=#ff0000>std::</font>cout &lt;&lt; "Hello world in ANSI-C++\n";<br>        return 0;<br>    }   <br>			</pre>
            </td>
            <td class=console vAlign=top width=250>Hello world in ANSI-C++ </td>
        </tr>
    </tbody>
</table>
</p>
<p>更常用的方法是使用using namespace ，这样我们就不必在所有标准空间中定义的函数或对象前面总是使用范围操作符::了 ：</p>
<p>
<table class=example cellSpacing=1 cellPadding=10 border=0>
    <tbody>
        <tr>
            <td class=program>
            <pre>    <font class=codecomment color=#008000>// ANSI-C++ compliant hello world (II)</font>
            #include &lt;iostream&gt;
            using namespace std;
            int main () {
            cout &lt;&lt; "Hello world in ANSI-C++\n";
            return 0;
            }
            </pre>
            </td>
            <td class=console vAlign=top width=250>Hello world in ANSI-C++ </td>
        </tr>
    </tbody>
</table>
</p>
<p>对于STL 用户，强烈建议使用ANSI-compliant 方式来包含标准函数库。 </p>
<img src ="http://www.cppblog.com/smallfa/aggbug/68833.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-08 12:33 <a href="http://www.cppblog.com/smallfa/archive/2008/12/08/68833.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>模板与多文件工程</title><link>http://www.cppblog.com/smallfa/archive/2008/12/08/68830.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Mon, 08 Dec 2008 04:03:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/08/68830.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68830.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/08/68830.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68830.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68830.html</trackback:ping><description><![CDATA[<div class=program>
<p>template &lt;class T&gt; <font class=codecomment>// 最常用的：一个class 参数。</font></p>
<p>template &lt;class T, class U&gt; <font class=codecomment>// 两个class 参数。</font></p>
<p>template &lt;class T, int N&gt; <font class=codecomment>// 一个class 和一个整数。</font></p>
<p>template &lt;class T = char&gt; <font class=codecomment>// 有一个默认值。</font></p>
<p>template &lt;int Tfunc (int)&gt; <font class=codecomment>// 参数为一个函数。</font></p>
</div>
<p>从编译器的角度来看，模板不同于一般的函数或类。<br><span style="COLOR: red">它们在需要时才被编译(compiled</span> on demand)，<br>也就是说一个模板的代码直到需要生成一个对象的时候(instantiation)才被编译。<br>当需要instantiation的时候，编译器根据模板为特定的调用数据类型生成一个特殊的函数。<br><br><br>当工程变得越来越大的时候，程序代码通常会被分割为多个源程序文件。<br>在这种情况下，<span style="COLOR: red">通常接口(interface)和实现(implementation)是分开的</span>。<br><br><br>用一个函数库做例子<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接口通常包括所有能被调用的函数的原型定义。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它们通常被定义在以.h 为扩展名的头文件 (header file) 中；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;而实现 (函数的定义)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;则在独立的C++代码文件中。<br><br><br></p>
<p>模板这种类似宏(macro-like) 的功能，<span style="COLOR: red">对多文件工程有一定的限制：</span><br>函数或类模板的实现 (定义) 必须与原型声明在<span style="COLOR: red">同一个文件中</span>。<br>也就是说我们不能再 将接口(interface)存储在单独的头文件中，<br>而必须将接口和实现放在使用模板的同一个文件中。</p>
<p>回到函数库的例子，如果我们想要建立一个函数模板的库，我们不能再使用头文件(.h) ，取而代之，我们应该生成一个模板文件(template file)，将函数模板的接口和实现 都放在这个文件中 (这种文件没有惯用扩展名，除了不要使用.h扩展名或不要不加任何扩展名)。<br><br><br><span style="COLOR: #0000ff">在一个工程中多次包含同时具有声明和实现的模板文件并不会产生链接错误 (linkage errors)，因为它们只有在需要时才被编译，而兼容模板的编译器应该已经考虑到这种情况，不会生成重复的代码。</span></p>
<img src ="http://www.cppblog.com/smallfa/aggbug/68830.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-08 12:03 <a href="http://www.cppblog.com/smallfa/archive/2008/12/08/68830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>静态成员(Static members)</title><link>http://www.cppblog.com/smallfa/archive/2008/12/04/68578.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Thu, 04 Dec 2008 10:34:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/04/68578.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68578.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/04/68578.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68578.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68578.html</trackback:ping><description><![CDATA[静态成员与全域变量(global variable)具有相同的属性，但它享有类(class)的范围<br><br><br><br><br><span style="COLOR: red">C++ 标准，为了避免它们被多次重复声明，<br>在class的声明中只能够包括static member的原型(声明)，<br>而不能够包括其定义(初始化操作)。<br>为了初始化一个静态数据成员，<br>我们必须在class之外(在全域范围内)，<br>包括一个正式的定义，就像上面例子中做法一样。</span> <br><br><br><br><br>
<p>在提醒一次，它其实是一个全域变量。唯一的不同是它的名字跟在class的后面。</p>
<p>就像我们会在class中包含static数据一样，我们也可以使它包含static 函数。<br>它们表示相同的含义：static函数是全域函数(global functions)，但是像一个指定class的对象成员一样被调用。<br>它们只能够引用static 数据，永远不能引用class的非静态(nonstatic)成员。<br>它们也不能够使用关键字this，因为this实际引用了一个对象指针，<br>但这些 static函数却不是任何object的成员，而是class的直接成员。</p>
<img src ="http://www.cppblog.com/smallfa/aggbug/68578.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-04 18:34 <a href="http://www.cppblog.com/smallfa/archive/2008/12/04/68578.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>定义一个class而没有明确定义构造函数的时候，编译器会自动假设两个重载的构造函数</title><link>http://www.cppblog.com/smallfa/archive/2008/12/04/68576.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Thu, 04 Dec 2008 10:04:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/04/68576.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68576.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/04/68576.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68576.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68576.html</trackback:ping><description><![CDATA[<p>实际上，当我们定义一个class而没有明确定义构造函数的时候，<br><br><br>编译器会自动假设两个重载的构造函数<br>&nbsp;(默认构造函数"default constructor" 和复制构造函数"copy constructor")。<br><br><br>例如，对以下class：</p>
<code>
<pre>   class CExample {<br>     public:<br>       int a,b,c;<br>       void multiply (int n, int m) { a=n; b=m; c=a*b; };<br>   };<br>   </pre>
<p>没有定义构造函数，<br><br><br>编译器自动假设它有以下constructor 成员函数：</p>
<ul>
    <li><span style="COLOR: red">Empty constructor</span>
    <p>它是一个没有任何参数的构造函数，被定义为nop (没有语句)。它什么都不做。</p>
    <code>CExample::CExample () { };</code>
    <li>
    <li><span style="COLOR: red">Copy constructor</span>
    <p style="COLOR: #0000ff">它是一个只有一个参数的构造函数，该参数是这个class的一个对象，这个函数的功能是将被传入的对象（object）的所有非静态（non-static）成员变量的值都复制给自身这个object。</p>
    <code>
    <pre>   CExample::CExample (const CExample&amp; rv) {<br>       a=rv.a;  b=rv.b;  c=rv.c;<br>   }<br>   </pre>
    </li>
</ul>
<p><strong class=important>必须注意：</strong>这两个默认构造函数（empty construction 和 copy constructor ）</p>
<p>只有在没有其它构造函数被明确定义的情况下才存在。</p>
<p>如果任何其它有任意参数的构造函数被定义了，这两个构造函数就都不存在了。</p>
<p>在这种情况下，</p>
<p>如果你想要有empty construction 和 copy constructor ，</p>
<p>就必需要自己定义它们。</p>
</code></code>
<img src ="http://www.cppblog.com/smallfa/aggbug/68576.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-04 18:04 <a href="http://www.cppblog.com/smallfa/archive/2008/12/04/68576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C在struct里面可以用public、private，默认的是public，而C++默认是private。</title><link>http://www.cppblog.com/smallfa/archive/2008/12/04/68575.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Thu, 04 Dec 2008 10:01:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/12/04/68575.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/68575.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/12/04/68575.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/68575.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/68575.html</trackback:ping><description><![CDATA[C在struct里面可以用public、private，默认的是public，而C++默认是private。<br><br>C在struct里面可以用public、private，默认的是public，而C++默认是private。
<img src ="http://www.cppblog.com/smallfa/aggbug/68575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-12-04 18:01 <a href="http://www.cppblog.com/smallfa/archive/2008/12/04/68575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>算法</title><link>http://www.cppblog.com/smallfa/archive/2008/11/27/67995.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Thu, 27 Nov 2008 08:31:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/27/67995.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67995.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/27/67995.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67995.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67995.html</trackback:ping><description><![CDATA[void main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;long a1 = 34, a2 = 23, a3 = 12;<br>&nbsp;&nbsp;&nbsp;&nbsp;if( a1 &gt; a2 )<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long temp = a1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a1 = a2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a2 = temp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;if( a1 &gt; a3 )<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long temp = a1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a1 = a3;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a3 = temp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;if( a2 &gt; a3 )<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long temp = a2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a2 = a3;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a3 = temp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br>上面就在每个if后面的复合语句中定义了一个临时变量temp以借助编译器的静态分配内存功能来提供临时存放卡片的内存。上面的元素交换并没有按照前面所说映射成函数，是因为在这里其只有三条语句且容易理解。如果要将交换操作定义为一函数<br>如果要将交换操作定义为一函数，则应如下：<br>void Swap( long *p1, long *p2 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void Swap( long &amp;r1, long &amp;r2 )<br>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;long temp = *p1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long temp = r1;<br>&nbsp;&nbsp;&nbsp;&nbsp;*p1 = *p2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r1 = r2;<br>&nbsp;&nbsp;&nbsp;&nbsp;*p2 = temp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r2 = temp;<br>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>void main()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void main()<br>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;long a1 = 34, a2 = 23, a3 = 12;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long a1 = 34, a2 = 23, a3 = 12;<br>&nbsp;&nbsp;&nbsp;&nbsp;if( a1 &gt; a2 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( a1 &gt; a2 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Swap( &amp;a1, &amp;a2 );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Swap( a1, a2 );<br>&nbsp;&nbsp;&nbsp;&nbsp;if( a1 &gt; a3 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( a1 &gt; a3 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Swap( &amp;a1, &amp;a3 );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Swap( a1, a3 );<br>&nbsp;&nbsp;&nbsp;&nbsp;if( a2 &gt; a3 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( a2 &gt; a3 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Swap( &amp;a2, &amp;a3 );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Swap( a2, a3 );<br>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;先看左侧的程序。上面定义了函数来表示给定盒子之间的交换操作，注意参数类型使用了long*，这里指针表示引用（应注意指针不仅可以表示引用，还可有其它的语义，以后会提到）。<br><br><br><br>下面看右侧的程序。参数类型变成long&amp;，和指针一样，依旧表示引用，但注意它们的不同。后者表示它是一个别名，即它是一个映射，映射的地址是记录作为参数的数字的地址，也就是说它要求调用此函数时，给出的作为参数的数字一定是有地址的数字<br>
<img src ="http://www.cppblog.com/smallfa/aggbug/67995.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-27 16:31 <a href="http://www.cppblog.com/smallfa/archive/2008/11/27/67995.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数</title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67941.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Wed, 26 Nov 2008 15:46:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67941.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67941.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67941.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67941.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67941.html</trackback:ping><description><![CDATA[<p>上面的返回类型为void，前面提过，void是C++提供的一种特殊数字类型，其仅仅只是为了保障语法的严密性而已，即任何函数执行后都要返回一个数字（后面将说明），而对于不用返回数字的函数，则可以定义返回类型为void，这样就可以保证语法的严密性。</p>
<p>可以认为函数类型的地址类型的数字编译器会隐式转换成指针类型的数字</p>
<p><br>重载函数表示函数名字一样，但参数类型及个数不同的多个函数</p>
<p>&nbsp;声明是告诉编译器一些信息，以协助编译器进行语法分析，避免编译器报错。而定义是告诉编译器生成一些代码，并且这些代码将由连接器使用。</p>
<p>extern long a, *pA, &amp;ra;<br>&nbsp;&nbsp;&nbsp; 上面就声明（不是定义）了三个变量a、pA和ra。<br>因为extern表示外部的意思，因此上面就被认为是告诉编译器有三个外部的变量，为a、pA和ra，故被认为是声明语句，所以上面将不分配任何内存。<br>同样，对于函数，它也是一样的：<br>&nbsp;&nbsp;&nbsp; extern void ABC( long );&nbsp; 或&nbsp; extern long AB( short b );<br></p>
<img src ="http://www.cppblog.com/smallfa/aggbug/67941.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 23:46 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67941.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类型修饰符（type-specifier）</title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67913.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Wed, 26 Nov 2008 07:52:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67913.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67913.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67913.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67913.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67913.html</trackback:ping><description><![CDATA[数组和指针都是类型修饰符，之前提过的引用变量的&#8220;&amp;&#8221;也是类型修饰符<br><br><strong>指针修饰符&#8220;*&#8221;</strong>——其总是接在变量名的前面，表示当前类型为原类型的指针。故：<br>short a = 10, *pA = &amp;a, **ppA = &amp;pA;<br><br><strong>&nbsp;引用修饰符&#8220;&amp;&#8221;</strong>——其总是接在变量名的前面，表示此变量不用分配内存以和其绑定，而在说明类型时，则不能有它，下面说明。由于表示相应变量不用分配内存以生成映射，故其不像上述两种类型修饰符，可以多次重复书写，因为没有意义<br>
<img src ="http://www.cppblog.com/smallfa/aggbug/67913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 15:52 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在堆上分配内存</title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67911.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Wed, 26 Nov 2008 07:40:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67911.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67911.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67911.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67911.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67911.html</trackback:ping><description><![CDATA[unsigned long *pA = new unsigned long; *pA = 10;<br>unsigned long *pB = new unsigned long[ *pA ];<br><br>上面就申请了两块内存，pA所指的内存（即pA的值所对应的内存）是4字节大小，而pB所指的内存是4*10=40字节大小。应该注意，由于new是一个操作符，其结构为new &lt;类型名&gt;[&lt;整型数字&gt;]。它返回指针类型的数字，其中的&lt;类型名&gt;指明了什么样的指针类型，而后面方括号的作用和定义数组时一样，用于指明元素的个数，但其返回的并不是数组类型，而是指针类型。<br><br><br><br>delete pA; delete[] pB;<br><br>&nbsp;&nbsp;&nbsp; 注意delete操作符并不返回任何数字，但是其仍被称作操作符，看起来它应该被叫做语句更加合适，但为了满足其依旧是操作符的特性，C++提供了一种很特殊的数字类型——void。其表示无，即什么都不是，这在《C++从零开始（七）》中将详细说明。因此delete其实是要返回数字的，只不过返回的数字类型为void罢了。<br><br>&nbsp;&nbsp;&nbsp; 注意上面对pA和pB的释放不同，因为pA按照最开始的书写，是new unsigned long返回的，而pB是new unsigned long[ *pA ]返回的。所以需要在释放pB时在delete的后面加上&#8220;[]&#8221;以表示释放的是数组，不过在VC中，不管前者还是后者，都能正确释放内存，无需&#8220;[]&#8221;的介入以帮助编译器来正确释放内存，因为以Windows为平台而开发程序的VC是按照Windows操作系统的方式来进行内存分配的，而Windows操作系统在释放内存时，无需知道欲释放的内存块的长度，因为其已经在内部记录下来（这种说法并不准确，实际应是C运行时期库干了这些事，但其又是依赖于操作系统来干的，即其实是有两层对内存管理的包装，在此不表）。<br>
<img src ="http://www.cppblog.com/smallfa/aggbug/67911.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 15:40 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67911.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>指针</title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67909.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Wed, 26 Nov 2008 07:39:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67909.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67909.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67909.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67909.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67909.html</trackback:ping><description><![CDATA[<p>再来看取内容操作符&#8220;*&#8221;，其右接的数字类型是指针类型或数组类型，它的计算就是将此指针类型的数字直接转换成地址类型的数字<br>因为指针类型的数字和地址类型的数字在数值上是相同的，仅仅计算规则不同</p>
<p><br>地址类型的数字是在编译时期给编译器用的<br>指针类型的数字是在运行时期给代码用的<br></p>
<img src ="http://www.cppblog.com/smallfa/aggbug/67909.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 15:39 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67909.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>申请内存   静态分配动态分配</title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67908.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Wed, 26 Nov 2008 07:38:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67908.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67908.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67908.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67908.html</trackback:ping><description><![CDATA[<p>在申请内存时总是申请固定大小的内存，则称此内存是静态分配的。前面提出的定义变量时，编译器帮我们从栈上分配的内存就属于静态分配</p>
<p><br>根据用户输入的不同而可能申请不同大小的内存时，则称此内存是动态分配的，后面说的从堆上分配就属于动态分配。</p>
<p><br>同样，静态分配的内存利用率不高或运用不够灵活，但代码容易编写且运行速度较快；动态分配的内存利用率高，不过编写代码时要复杂些，需自己处理内存的管理（分配和释放）且由于这种管理的介入而运行速度较慢并代码长度增加。<br>静态和动态的意义不仅仅如此，其有很多的深化，如硬编码和软编码、紧耦合和松耦合，都是静态和动态的深化。<br></p>
<img src ="http://www.cppblog.com/smallfa/aggbug/67908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 15:38 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串 </title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67907.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Wed, 26 Nov 2008 07:37:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67907.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67907.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67907.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67907.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67907.html</trackback:ping><description><![CDATA[<p>&nbsp;char类型进行表示的字符串称为单字节字符串（SingleByte），用这种表示方式记录的文本文件称为是ANSI格式的<br></p>
<p>&nbsp;&nbsp;多字节字符串（MultiByte），用这种表示方式记录的文本文件称为是MBCS格式的<br></p>
<p>&nbsp;宽字节字符串（WideChar），用这种表示方式记录的文本文件称为是Unicode格式的<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (一个short类型的数字来表示，即每个字符的长度固定为2字节)</p>
<img src ="http://www.cppblog.com/smallfa/aggbug/67907.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 15:37 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67907.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在线C++编译器介绍</title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67894.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Wed, 26 Nov 2008 04:35:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67894.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67894.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67894.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67894.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67894.html</trackback:ping><description><![CDATA[<p>下面的网址是最有名的两个在线C++编译网站：</p>
<p><a href="http://www.dinkumware.com/exam/default.aspx">http://www.dinkumware.com/exam/default.aspx</a> <br><a href="http://www.comeaucomputing.com/tryitout/">http://www.comeaucomputing.com/tryitout/</a><br>许多在线判题系统也可以用来进行在线编译：</p>
<p><a href="http://acm.zju.edu.cn/">http://acm.zju.edu.cn/</a> <br><a href="http://acm.pku.edu.cn/JudgeOnline/">http://acm.pku.edu.cn/JudgeOnline/</a> <br><a href="http://acm.uva.es/">http://acm.uva.es/</a><br>你可能会好奇这些网站使用的编译器的版本和编译参数到底是什么。有些网站会提供这些信息，而有些则不会。那么你就只能靠自己去发现这些&#8220;秘密&#8221;了。</p>
<p>工欲善其事，必先利其器。让我们先看看一些从编译器获取信息的小技巧。</p>
<p>1. 输出宏<br>在C++中， 字符串常数不能作为模板参数。大多数编译器会在错误信息中同时输出字符串的内容。下面的代码展示了这一技巧。 </p>
<p>template&lt;const char *&gt; class A {};<br>#define F0(x) #x<br>#define F1(x) F0(x)<br>#define V1 F1(__GNUC__)<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; A&lt;V1&gt; a1;<br>}</p>
<p><br>这里，宏F0和F1用于将整型转换成字符串。编译器会输出类似于"literal "3" is not a valid template argument because it is the address of an object with static linkage"的出错信息。里面的"3"就是你想知道的宏的内容。 </p>
<p>2. 输出常数<br>同样，浮点数是不能作为模板参数的。编译器通常会在错误信息中包含浮点数的值。利用这一点，我们可以输出浮点常数。不过很不幸的是，VC会隐式的将浮点类型的模板参数转换成int（参见<a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296008">https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296008</a>）<br>下面是一种输出整型常量的方法： </p>
<p>template&lt;int N&gt;<br>class A<br>{<br>private:<br>&nbsp;&nbsp;&nbsp; A();<br>};<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; A&lt;sizeof(char)&gt; a;<br>}</p>
<p><br>3. 输出变量类型<br>有时候，你可能需要知道某些变量的实际类型，这时候你可以使用下面的代码： </p>
<p>struct Dummy {};<br>void Fun(const Dummy &amp;);<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; Fun(1+1U);<br>}</p>
<p><br>PS：如果你使用的是gcc，那么它会输出"not convert `2' to `const Dummy&amp;'"，所以你需要将Fun的声明改成"template&lt;typename T&gt; void Fun(T);"（换句话说，在gcc中上面的代码也可以用于输出常数的值） </p>
<p>4. 输出包含路径<br>如果要获取STL头文件的路径，你可以使用： </p>
<p>#include &lt;ext/hash_set&gt;<br>using __gnu_cxx::hash_set; </p>
<p>int main()<br>{<br>&nbsp;&nbsp;&nbsp; hash_set&lt;&gt; m;<br>}</p>
<p>&nbsp;</p>
<p>PS：这里也可以使用vector。 </p>
<p>好，现在是时候牛刀小试了。关于如何获取编译器的版本信息，可以参考这篇文章：Pre-defined Compiler Macros</p>
<p>下面是利用上面介绍的技巧获得的dinkumware网站的一些资料： </p>
<p>1. VC <br>版本 (_MSC_FULL_VER)：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VC8 140050727 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VC7.1 13103077 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VC7 13009466 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VC6 12008804 <br>包含路径： <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D:\cplt501_vc_source\include (with _CPPLIB_VER=501) </p>
<p>2. EDG<br>版本(__EDG_VERSION__):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.05&nbsp; <br>编译参数：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; edgcc --alt -D_WIN32 -D_M_IX86 --no_inlining --diag_suppress=1290 --long_long --wchar_t_keyword -D_C99 -ID:\cplt501_gen_source/include/c -ID:\cplt501_gen_source/include -IC:\PROGRA~1\MICROS~2.NET\VC7/include --exceptions --microsoft -c sourceFile.cpp <br>因为使用了VC兼容模式进行编译，所以编译器可能会模拟VC的部分bug </p>
<p>3. GCC<br>版本：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.2.0 <br>包含路径：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D:/cplt501_gen_source/include and D:/Mingw/include/c++/3.2/<br>可以看到这里使用的GCC的版本已经相当陈旧了</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br>文章出处：<a href="http://www.diybl.com/course/3_program/c++/cppsl/2008108/149011.html">http://www.diybl.com/course/3_program/c++/cppsl/2008108/149011.html</a></p>
<img src ="http://www.cppblog.com/smallfa/aggbug/67894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 12:35 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67894.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>赋值语句</title><link>http://www.cppblog.com/smallfa/archive/2008/11/26/67857.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Tue, 25 Nov 2008 16:18:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/26/67857.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67857.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/26/67857.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67857.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67857.html</trackback:ping><description><![CDATA[<p>赋值语句<br>因此应在变量定义的时候就进行赋值（但是会有性能上的影响，不过很小），以初始化变量而防止出现莫名其妙的值,在表达式中运用赋值运算符是不好的，即使它可能让你写出看起来简练的语句，但它也使代码的可维护性降低。</p>
<p><br>true 0<br>false 非0</p>
<img src ="http://www.cppblog.com/smallfa/aggbug/67857.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-26 00:18 <a href="http://www.cppblog.com/smallfa/archive/2008/11/26/67857.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>栈（Stack）   堆（Heap）</title><link>http://www.cppblog.com/smallfa/archive/2008/11/24/67743.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Mon, 24 Nov 2008 10:45:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/24/67743.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/67743.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/24/67743.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/67743.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/67743.html</trackback:ping><description><![CDATA[<br><span style="COLOR: #0000ff">C++即允许程序员有两种向操作系统申请内存的方式。<br></span>&nbsp;&nbsp;&nbsp; 前一种就是在栈上分配，申请的内存大小<span style="COLOR: #ff0000">固定不变</span>。<br>&nbsp;&nbsp;&nbsp;&nbsp;后一种是在堆上分配，<span style="COLOR: #ff0000">申请的内存大小可以在运行的时候变化</span>，不是固定不变的<br>_______+++++++++++++++++++++++++++++++++++_____________________________<br><br><br><br><br><strong>栈（Stack）<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 任何程序执行前，<span style="COLOR: red">预先分配</span>一固定长度的内存空间，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这块内存空间被称作栈,也被叫做堆栈<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 即程序员自己判断可以使用哪些内存，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而<span style="COLOR: red">不是</span>操作系统,很明显，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面的工作是<span style="COLOR: red">由编译器来做</span>的，&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 工作只是从操作系统变到程序自己而已,<br><span style="COLOR: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 好处</span>就是由于程序一开始执行时就已经分配了一大块连续内存,<br><span style="COLOR: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 坏处</span>也就是只能在编译时期分配内存<br><br><br><span style="COLOR: #0000ff">上面的工作是编译器做的，即程序员并不参与堆栈的维护。但上面已经说了，堆栈相当于在编译时期分配内存，因此一旦计算好某块内存的偏移，则这块内存就只能那么大，不能变化了<br><br><br>__________________________________________________________________________________________________<br><br><font color=#000000><strong>堆（Heap）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>在Windows操作系统下，由<span style="COLOR: #ff0000">操作系统分配的内存就叫做堆</span>，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而栈可以认为是在程序开始时就分配的堆<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因此在堆上就可以分配大小变化的内存块，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因为是<span style="COLOR: #ff0000">运行时期</span>即时分配的内存，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而<span style="COLOR: #ff0000">不是编译时期</span>已计算好大小的内存块。<br></font></span>
<img src ="http://www.cppblog.com/smallfa/aggbug/67743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-24 18:45 <a href="http://www.cppblog.com/smallfa/archive/2008/11/24/67743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++  开blogs</title><link>http://www.cppblog.com/smallfa/archive/2008/11/11/66606.html</link><dc:creator>henry08</dc:creator><author>henry08</author><pubDate>Tue, 11 Nov 2008 07:35:00 GMT</pubDate><guid>http://www.cppblog.com/smallfa/archive/2008/11/11/66606.html</guid><wfw:comment>http://www.cppblog.com/smallfa/comments/66606.html</wfw:comment><comments>http://www.cppblog.com/smallfa/archive/2008/11/11/66606.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/smallfa/comments/commentRss/66606.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/smallfa/services/trackbacks/66606.html</trackback:ping><description><![CDATA[c++&nbsp; 开blogs
<img src ="http://www.cppblog.com/smallfa/aggbug/66606.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/smallfa/" target="_blank">henry08</a> 2008-11-11 15:35 <a href="http://www.cppblog.com/smallfa/archive/2008/11/11/66606.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>