﻿<?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++博客-MyMSDN-随笔分类-C++ Primer 学习笔记</title><link>http://www.cppblog.com/mymsdn/category/4479.html</link><description>MyMSDN记录开发新知道</description><language>zh-cn</language><lastBuildDate>Sun, 04 Apr 2010 17:01:53 GMT</lastBuildDate><pubDate>Sun, 04 Apr 2010 17:01:53 GMT</pubDate><ttl>60</ttl><item><title>将数组作为实参传递</title><link>http://www.cppblog.com/mymsdn/archive/2009/02/19/74333.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 19 Feb 2009 13:35:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/02/19/74333.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/74333.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/02/19/74333.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/74333.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/74333.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p>在C++中我们应该少用指针，多用引用，原因请大家自行搜索。在传递数组的时候我们需要格外注意，先让我们看一个简单的范例。</p><pre class="gc-code"><span style="color: green">// PassArray.cpp : 定义控制台应用程序的入口点。
//

</span><span style="color: blue">#include </span><span style="color: #a31515">"stdafx.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;iostream&gt;

</span><span style="color: blue">using namespace </span>std;

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Func1(T, T);
<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Func2(T&amp;, T&amp;);
<span style="color: blue">void </span>Func3(<span style="color: blue">int </span>(&amp;)[10], <span style="color: blue">int </span>(&amp;)[12]);

<span style="color: blue">int </span>_tmain(<span style="color: blue">int </span>argc, _TCHAR* argv[])
{
    <span style="color: blue">int </span>a[10], b[12];

    Func1(a, b);
    <span style="border-bottom: yellow 1px solid; border-left: yellow 1px solid; color: red; border-top: yellow 1px solid; border-right: yellow 1px solid">Func2(a, b);</span>
    Func3(a, b);

    <span style="color: blue">return </span>0;
}

<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Func1(T, T)
{
    cout&lt;&lt;<span style="color: #a31515">"Func1.invoked!"</span>&lt;&lt;endl;
}
<span style="color: blue">template </span>&lt;<span style="color: blue">typename </span>T&gt;
<span style="color: blue">void </span>Func2(T&amp;, T&amp;)
{
    cout&lt;&lt;<span style="color: #a31515">"Func2.invoked!"</span>&lt;&lt;endl;
}
<span style="color: blue">void </span>Func3(<span style="color: blue">int </span>(&amp;m)[10], <span style="color: blue">int </span>(&amp;n)[12])
{
    cout&lt;&lt;<span style="color: #a31515">"Func3.invoked!"</span>&lt;&lt;endl;
}</pre>
<p>首先这个范例无法编译通过：</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/d6325f77f4c8_12F7F/image_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="error C2782" border="0" alt="error C2782" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/d6325f77f4c8_12F7F/image_thumb.png" width="435" height="41"></a> </p>
<p>原因就出在类型推断上。根据定义，Func2的类型必须是T&amp;，也就是说传递实参的时候，两个形参必须是相同的，而这一点在模板编程中就会由编译器来负责推断。</p>
<p>Func1：</p>
<p>调用Func1(a, b)则推断的类型分别是Func1(int*, int*)，调用函数将会自动将数组的首地址指针作为实参进行传递，因此类型推断两形参相同，编译通过！</p>
<p>Func2：</p>
<p>调用Func2(a, b)因为我们希望按引用的方式进行实参传递，因此需要遵循这样的规律：</p>
<p class="note">（P208）如果形参是数组的引用，编译器将不会将数组实参转化为指针，而是传递数组引用的本身。在这种情况下，数组大小成为形参和实参类型的一部分。</p>
<p>所以推断类型分别是Func2(int (&amp;)[10], int (&amp;)[12])，因为int (&amp;)[10] != int (&amp;)[12]，所以与T == T相悖！自然也就编译不过了！</p>
<p>Func3：</p>
<p>该函数是Func2的一个静态表示，通过上面的解释应该很容易理解这个代码了。</p><img src ="http://www.cppblog.com/mymsdn/aggbug/74333.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-02-19 21:35 <a href="http://www.cppblog.com/mymsdn/archive/2009/02/19/74333.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ notes (6)</title><link>http://www.cppblog.com/mymsdn/archive/2009/02/15/cpp-notes-6.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sat, 14 Feb 2009 18:28:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/02/15/cpp-notes-6.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/73828.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/02/15/cpp-notes-6.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/73828.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/73828.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p>51、static成员函数</p> <p>因为static成员不是任何对象的组成部分，所以static成员函数不能被声明为const。毕竟，将成员函数声明为const就是承诺不会修改该函数所属的对象。最后，static成员函数也不能被声明为虚函数。</p> <p>52、特殊的整型const static成员（P401）</p> <p class="quote">const static数据成员在类的定义体中初始化时，该数据成员仍必须在类的定义体之外进行定义。</p> <div class="gc-code"> <p>class Accout{</p> <p>public:</p> <blockquote> <p>static double rate() { return interestRate;}</p> <p>static void rate(double); //sets a new rate</p></blockquote> <p>private:</p> <blockquote> <p>static const int period = 30; //interest posted every 30 days</p> <p>double daily_tbl[period]; // ok: period is constant expression</p></blockquote> <p>}</p> <p>//definition of static member with no initializer;</p> <p>//the initial value is specified inside the class definition</p> <p>const int Accout::period;</p></div> <p>但在gcc和MS vc++编译器下<em>似乎</em>均不需要再次定义，也就是题设的&#8220;必须&#8221;二字在此失效。</p> <p>53、操作符重载（P435）</p> <p>下面是一些指导原则，有助于决定将操作符设置为类成员还是普通非成员函数</p> <ul> <li>赋值（=）、下标（[]）、调用（()）和成员访问箭头（-&gt;）等操作符必须定义为成员，将这些操作符定义为非成员函数将在编译时标记为错误。  <li>像赋值一样，复合赋值操作符通常应定义为类的成员。与赋值不同的是，不一定非得这样做，如果定义非成员复合赋值操作符，不会出现编译错误。  <li>改变对象状态或与给定类型紧密联系的其他一些操作符，如自增、自减和解引用，通常应定义为类成员。  <li>对称的操作符，如算术操作符、相等操作符、关系操作符和位操作符，最好定义为普通非成员函数。</li></ul> <p>54、区别操作符的前缀和后缀形式（P447）</p> <p>同时定义前缀式操作符和后缀式操作符存在一个问题：它们的形参数目和类型相同，普通重载不能区别所定义的是前缀式操作符还是后缀式操作符。</p> <p>为解决这一问题，后缀式操作符函数接受一个额外的（即，无用的）int型形参。使用后缀操作符时，编译器提供0作为这个形参的实参。尽管我们的前缀式操作符函数可以使用这个额外的形参，但通常不应该这样做。那个形参不是后缀式操作符的正常工作所需要的，它的唯一目的是使后缀函数与前缀函数区别开来。</p> <p>55、显式调用前缀式操作符</p> <div class="gc-code"> <p>CheckedPtr parr(ia, ia+size); //ia points to an array of ints</p> <p>parr.operator(0); //call postfix operator++</p> <p>parr.operator(); //call prefix operator++</p></div> <p>56、函数对象（P450）</p> <div class="gc-code"> <p>struct absInt {</p> <blockquote> <p>int operator() (int val){</p></blockquote> <blockquote> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return val&lt;0 ? &#8211;val : val;</p></blockquote> <blockquote> <p>}</p></blockquote> <p>};</p> <p>int i = &#8211;42;</p> <p>absInt absObj; //object that defines function call operator</p> <p>unsigned int ui = absObj(i); //calls absInt::operator(int)</p></div> <p>尽管absObj是一个对象而不是函数，我们仍然可以&#8220;调用&#8221;该对象，效果是运行由absObj对象定义的重载调用操作符，该操作符接受一个int值并返回它的绝对值。</p> <p>函数对象经常用作通用算法的实参。（详见P450）</p> <p>57、函数对象的函数适配器（P453）</p> <p>标准库提供了一组函数适配器（function adapter），用于特化和扩展一元和二元函数对象。函数适配器分为如下两类：</p> <p>（1）绑定器（binder），是一种函数适配器，它通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数对象。（<a href="http://msdn.microsoft.com/en-us/library/sh813d0y(VS.80).aspx">bind1st</a>和<a href="http://msdn.microsoft.com/en-us/library/3f0defz2.aspx">bind2nd</a>&nbsp;<a href="http://www.google.cn/search?hl=zh-CN&amp;newwindow=1&amp;q=bind1st+bind2nd&amp;btnG=Google+%E6%90%9C%E7%B4%A2&amp;meta=&amp;aq=f&amp;oq=" target="_blank">更多</a>）</p> <p>（2）求反器（negator），是一种函数适配器，它将谓词函数对象的真值求反。（<a href="http://msdn.microsoft.com/en-us/library/syyszzf8(VS.80).aspx" target="_blank">not1</a>和<a href="http://msdn.microsoft.com/en-us/library/8bts2xks(VS.80).aspx" target="_blank">not2</a>&nbsp;<a href="http://www.google.cn/search?hl=zh-CN&amp;newwindow=1&amp;q=stardard+c%2B%2B+library+negator+not1+not2+&amp;btnG=Google+%E6%90%9C%E7%B4%A2&amp;meta=&amp;aq=f&amp;oq=" target="_blank">更多</a>）</p> <p>58、转换操作符（P455）</p> <p>转换为什么有用？（详见P454）</p> <p>转换函数采用如下通用形式：</p> <p>operator type();</p> <p>这里，type表示内置类型名、类类型名或由类型别名所定义的名字。对任何可作为函数返回类型的类型（除了void之外）都可以定义转换函数。一般而言，不允许转换为数组或函数类型，转换为指针（数据或函数指针）以及引用类型是可以的。</p> <p class="quote">转换函数必须是成员函数，不能指定返回类型，并且形参表必须为空。</p> <p class="quote">转换函数一般不应该改变被转换的对象。因此，转换操作符通常应定义为const成员。</p> <p>59、只能应用一个类类型转换</p> <p>类类型转换之后不能再跟另一个类类型转换。如果需要多个类类型转换，则代码将出错。</p> <p>假设有Integral=&gt;SmallInt=&gt;int，但是如果有一个函数cal(int)，那么对于SmallInt si，可以使用cal(si)，但对于Integral intVal;则不能使用cal(intVal)。语言只允许一次类类型转换，所以该调用出错。</p> <p>60、virtual与其他成员函数（P479）</p> <p>C++中的函数调用默认不使用动态绑定。要触发动态绑定，必须满足两个条件：第一，只有指定为虚函数的成员函数才能进行动态绑定，成员函数默认为非虚函数，非虚函数不进行动态绑定；第二，必须通过基类类型的引用或指针进行函数调用。</p> <p class="quote">基类类型引用和指针的关键点在于静态类型（static type，在编译时可知的引用类型或指针类型）和动态类型（dynamic type，指针或引用所绑定的对象的类型，这是仅在运行时可知的）可能不同。</p> <img src ="http://www.cppblog.com/mymsdn/aggbug/73828.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-02-15 02:28 <a href="http://www.cppblog.com/mymsdn/archive/2009/02/15/cpp-notes-6.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ notes (5)</title><link>http://www.cppblog.com/mymsdn/archive/2009/02/12/cpp-notes-5.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Wed, 11 Feb 2009 17:06:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/02/12/cpp-notes-5.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/73512.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/02/12/cpp-notes-5.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/73512.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/73512.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p>41、vector、list、deque的性能初窥</p><pre class="gc-code"><span style="color: #7f0055">int </span>large_size = 10000000;

cout_current_time(<span style="color: #2a00ff">"start init vector!\t"</span>);
<span style="color: #005032">vector</span>&lt;<span style="color: #005032">string</span>&gt; svec1(large_size, <span style="color: #2a00ff">"Hello"</span>);
<span style="color: #005032">vector</span>&lt;<span style="color: #005032">string</span>&gt; svec2(large_size, <span style="color: #2a00ff">"Hi"</span>);
cout_current_time(<span style="color: #2a00ff">"end init vector!\t"</span>);

cout_current_time(<span style="color: #2a00ff">"start init list!\t"</span>);
<span style="color: #005032">list</span>&lt;<span style="color: #005032">string</span>&gt; slist1(large_size, <span style="color: #2a00ff">"Hello"</span>);
<span style="color: #005032">list</span>&lt;<span style="color: #005032">string</span>&gt; slist2(large_size, <span style="color: #2a00ff">"Hi"</span>);
cout_current_time(<span style="color: #2a00ff">"end init list!\t"</span>);

cout_current_time(<span style="color: #2a00ff">"start init deque!\t"</span>);
<span style="color: #005032">deque</span>&lt;<span style="color: #005032">string</span>&gt; sdeq1(large_size, <span style="color: #2a00ff">"Hello"</span>);
<span style="color: #005032">deque</span>&lt;<span style="color: #005032">string</span>&gt; sdeq2(large_size, <span style="color: #2a00ff">"Hi"</span>);
cout_current_time(<span style="color: #2a00ff">"end init deque!\t"</span>);<br></pre>
<p>用事实说话最有说服力：</p><pre class="code">start init vector!    current time : 5:5:52
end init vector!    current time : 5:5:55
start init list!    current time : 5:5:55
end init list!    current time : 5:6:14
start init deque!    current time : 5:6:14
end init deque!    current time : 5:6:26</pre>
<p><a href="http://11011.net/software/vspaste"></a>可以看出大致时间比例为3/19/12。虽然不足以佐证它们的性能差距，但vector的常用似乎有了更充分的理由。</p>
<p>这里使用了一个简单的时间函数大致如下：</p><pre class="gc-code"><span style="background: #e8f2fe; color: #7f0055">#include </span><span style="background: #e8f2fe; color: #2a00ff">&lt;time.h&gt;</span>
<span style="color: #7f0055"><br>typedef struct </span><span style="color: #005032">tm </span>* <span style="color: #005032">time_type</span>;
<span style="color: #005032">time_type </span>get_current_time(<span style="color: #7f0055">void</span>) {
    <span style="color: #005032">time_t </span>t;

    t = <span style="color: #642880">time</span>(NULL);
    <span style="color: #7f0055">return </span><span style="color: #642880">localtime</span>(&amp;t);
}</pre>
<p>42、容器自增长（P286）</p>
<p class="quote">每种实现都要求遵循以下原则：确保push_back操作高效地在vector中添加元素。从技术上来说，在原来为空的vector容器上n次调用push_back函数，从而创建拥有n个元素的vector容器，其执行时间永远不能超过n的常量倍。</p>
<p>43、类定义中为何不能具有自身的数据成员（P375）</p>
<p class="quote">因为只有当类定义体完成后才能定义类，因此类不能具有自身类型的数据成员。然而，只要类名一出现就可以认为该类已声明。因此，类的数据成员可以是指向自身类型的指针或引用：</p>
<div class="gc-code">
<p>class LinkScreen {</p>
<blockquote>
<p>Screen window;</p>
<p>LinkScreen *next;</p>
<p>LinkScreen *prev;</p></blockquote>
<p>};</p></div>
<p>44、两种引用类类型的方法（P376）</p>
<p>Sales_item item1; //default initialized object of type Sales_item</p>
<p>class Sales_item item1; //equivalent definition of item1</p>
<p>两种引用类类型的方法是等价的。第二种方法是从C继承而来的，在C++中仍然有效。第一种更为简练，由C++语言引入，使得类类型更容易使用。</p>
<p>45、为什么类的定义以分号结束（P376）</p>
<p>分号是必须的，因为在类定义之后可以接一个对象定义列表。定义必须以分号结束：</p>
<p>class Sales_item {/* &#8230; */};</p>
<p>class Sales_item {/* &#8230; */} accum, trans;</p>
<p>46、形参表和函数体处于类作用域中，函数返回类型不一定在类作用域中</p>
<p>在定义于类外部的成员函数中，形参表和成员函数体都出现在成员名之后。这些都是在类作用域中定义，所以可以不用限定而引用其他成员。因为形参表是在Screen类作用域内，所以不必知名我们想要的是Screen::index。</p>
<p>如果返回类型使用由类定义的类型，则必须使用完全限定名。</p><pre class="gc-code"><span style="color: blue">#include </span><span style="color: #a31515">"stdafx.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;iostream&gt;

</span><span style="color: blue">class </span>MyClass
{
<span style="color: blue">public </span>:
    <span style="color: blue">typedef int </span>index_t;
    index_t twice(index_t in);
};

<strong>MyClass::</strong>index_t MyClass ::twice(index_t in)
{
    <span style="color: blue">return </span>in * 2;
}

<span style="color: blue">int </span>_tmain(<span style="color: blue">int </span>argc, _TCHAR* argv[])
{
    <span style="color: blue">using namespace </span>std; 
    
    MyClass obj;
    MyClass::index_t x, y;
    
    x = 10;
    y = obj.twice(x);

    cout&lt;&lt;<span style="color: #a31515">"x = "</span>&lt;&lt;x&lt;&lt;<span style="color: #a31515">"; y = "</span>&lt;&lt;y&lt;&lt;<span style="color: #a31515">";"</span>&lt;&lt;endl;

    <span style="color: blue">return </span>0;
}</pre>
<p>47、构造函数初始化式（P387）</p>
<p>与任意的成员函数一样，构造函数可以定义在类的内部或外部。构造函数初始化式只在构造函数的定义中而不是声明中指定。</p>
<p>构造函数初始化列表难以理解的一个原因在于，省略初始化列表并在构造函数的函数体内对数据成员赋值是合法的。</p>
<p>在构造函数初始化列表中没有显式提及的每个成员，使用与初始化变量相同的规则来进行初始化。运行该类型的默认构造函数，来初始化类类型的数据成员。内置或复合类型的成员的初始值依赖于对象的作用域：在局部作用域中这些成员不被初始化，而在全局作用域中它们被初始化为0。</p>
<p>如果那个类没有默认构造函数，则编译器尝试使用默认构造函数将会失败。在这种情况下，为了初始化数据成员，必须提供初始化式。</p>
<p>对于这样的成员，在构造函数函数体中对它们赋值不起作用。没有默认构造函数的类类型成员，以及const或引用类型的成员，不管是哪种类型，都必须在构造函数初始化列表中进行初始化。</p>
<p>因为内置类型的成员不进行隐式初始化，所以对这些成员是进行初始化还是赋值似乎都无关紧要。除了两个例外，对非类类型的数据成员进行赋值或使用初始化式在结果和性能上都是等价的。</p>
<p>48、成员初始化的次序</p>
<p>构造函数初始化列表仅指定用于初始化成员的值，并不指定这些初始化执行的次序。成员被初始化的次序就是定义成员的次序。</p>
<div class="gc-code">
<p>class X{</p>
<blockquote>
<p align="left">int i;</p>
<p align="left">int j;</p></blockquote>
<p align="left">public:</p>
<blockquote>
<p align="left">//run-time error: i is initialized before j</p>
<p align="left">X(int val): j(val), i(j) {}</p></blockquote>
<p>}</p></div>
<p>在这种情况下，构造函数初始化列表看起来似乎是用val初始化j，然后再用j来初始化i。然而i首先被初始化。这个初始化列表的效果是用尚未初始化的j值来初始化i！</p>
<p>49、使用默认构造函数（P393）</p>
<p>常犯的一个错误是采用以下方式声明一个用默认构造函数初始化的对象：</p>
<p>Sales_item myobj();</p>
<div class="gc-code">
<p>Sales_item myobj(); //ok: but defines a function, not an object</p>
<p>if(myobj.same_isbn(Primer_3rd_ed)) // error: myobj is a function</p></div>
<p>正确的方式应该是去掉相应的括号：</p>
<p class="gc-code">Sales_item myobj;</p>
<p>或者</p>
<p class="gc-code">Sales_item myobj = Sales_item();</p>
<p>50、显式或隐式初始化</p><pre class="gc-code"><span style="color: blue">#include </span><span style="color: #a31515">"stdafx.h"
</span><span style="color: blue">#include </span><span style="color: #a31515">&lt;iostream&gt;
</span><span style="color: blue">using namespace </span>std; 
<span style="color: blue">class </span>MyClass
{
<span style="color: blue">public </span>:
    <span style="color: blue">typedef int </span>index_t;
    <span style="color: blue">bool </span>same_object(MyClass obj);

<span style="color: blue">public </span>:
    MyClass(<span style="color: blue">int </span>default_index = 5)
        :default_index(default_index),
        m_name(<span style="color: #a31515">"default_name"</span>){}
    MyClass::MyClass(std::string name);

<span style="color: blue">public </span>:
    <span style="color: blue">int </span>default_index;
    std::string m_name;
};

MyClass::MyClass(std::string name)
        :default_index(0), m_name(name){}

<span style="color: blue">bool </span>MyClass::same_object(MyClass obj)
{
    cout&lt;&lt;<span style="color: #a31515">"m_name = "</span>&lt;&lt;m_name.c_str()&lt;&lt;endl;
    cout&lt;&lt;<span style="color: #a31515">"obj.m_name = "</span>&lt;&lt;obj.m_name.c_str()&lt;&lt;endl;
    <span style="color: blue">return </span>strcmp(obj.m_name.c_str(), m_name.c_str()) == 0;
}

<span style="color: blue">int </span>_tmain(<span style="color: blue">int </span>argc, _TCHAR* argv[])
{    
    MyClass obj;

    cout&lt;&lt;<span style="color: #a31515">"explicit : "</span>&lt;&lt;obj.same_object(MyClass(<span style="color: #a31515">"default_name"</span>))&lt;&lt;endl;
    cout&lt;&lt;<span style="color: #a31515">"implicit : "</span>&lt;&lt;obj.same_object(string(<span style="color: #a31515">"default_name"</span>))&lt;&lt;endl;

    <span style="color: blue">return </span>0;
}</pre>
<p>因为具有以std::string为形参的构造函数，因此在调用需要MyClass对象的same_object成员函数时，会自动隐式调用该构造函数构建MyClass对象，用于操作。但生成的MyClass对象是临时对象，在same_object函数调用完成后销毁。如果为了避免产生隐式转换可以使用explicit关键字来抑制由构造函数定义的隐式转换：</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/Cnotes5_3677/image_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="explicit" border="0" alt="explicit" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/Cnotes5_3677/image_thumb.png" width="617" height="189"></a></p> <img src ="http://www.cppblog.com/mymsdn/aggbug/73512.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-02-12 01:06 <a href="http://www.cppblog.com/mymsdn/archive/2009/02/12/cpp-notes-5.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ notes (4)</title><link>http://www.cppblog.com/mymsdn/archive/2009/02/05/cpp-notes-4.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Wed, 04 Feb 2009 19:48:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2009/02/05/cpp-notes-4.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/73033.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2009/02/05/cpp-notes-4.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/73033.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/73033.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p>31、动态空间的释放（P119）</p> <p>动态空间的释放使用delete [] pia;（其中pia为指向动态分配的数组的第一个元素的指针）。在关键字delete和指针之间的方括号对是必不可少的：它告诉编译器该指针指向的是自由存储区中的数组，而并非单个对象。</p> <p class="note">如果遗漏了空方括号对，这是一个编译器无法发现的错误，将导致程序在运行时出错。</p> <p>使用std::string后则会自动进行释放，无需delete！</p> <p>32、c_str返回的数组并不保证一定是有效的……</p><pre class="gc-code">std::string st1(<span style="color: #a31515">"I am a string object!"</span>);
<span style="color: green">//error C2440: “初始化”: 无法从“const char *”转换为“char *”
//char *str = st1.c_str();
</span><span style="color: blue">const char </span>*cstr = st1.c_str();
std::cout&lt;&lt;cstr&lt;&lt;std::endl;</pre>
<p class="note">c_str返回的数组并不保证一定是有效的，接下来对st1的操作有可能会改变st1的值，使刚才返回的数组失效。如程序需要持续访问该数据，则应该复制c_str函数返回的数组。</p>
<p>33、指向函数的指针</p>
<p>详见《<a href="http://www.cppblog.com/mymsdn/archive/2009/02/01/pointer-to-function.html">指向函数的指针的一点理解</a>》</p>
<p>34、容器初始化</p>
<p>在大多数的程序中，使用默认构造函数能达到最佳运行时性能，并且使容器更容易使用。</p>
<p>35、容器头文件</p>
<p>#include &lt;vector&gt;</p>
<p>#include &lt;list&gt;</p>
<p>#include &lt;deque&gt; //双端队列“double-ended queue”，发音为“deck”</p>
<p>标准库定义了以上三种顺序容器类型。</p>
<p>36、容器的容器</p>
<p>必须用空格隔开两个相邻的&gt;符号，以示这是两个分开的符号，否则，系统会认为&gt;&gt;是单个符号，为右移操作符，并导致编译时错误。</p><pre class="gc-code"><span style="color: #7f0055">int </span>m, n;
m = 5;
n = 3;

cout &lt;&lt; <span style="color: #2a00ff">"Print a line!" </span>&lt;&lt; endl;
<span style="color: #005032">vector</span>&lt;<span style="color: #005032">string</span>&gt; lines(n, <span style="color: #2a00ff">" I_am_a_PC_! "</span>);
<span style="color: #7f0055">for </span>(<span style="color: #005032">vector</span>&lt;<span style="color: #005032">string</span>&gt;::<span style="color: #005032">iterator </span>siter = lines.begin(); siter != lines.end(); ++siter) {
    cout &lt;&lt; *siter;
}
cout &lt;&lt; endl;

cout &lt;&lt; <span style="color: #2a00ff">"Print a paragraph!" </span>&lt;&lt; endl;
<span style="color: #005032">vector</span>&lt;<span style="color: #005032">vector</span>&lt;<span style="color: #005032">string</span>&gt; &gt; paragraph(m, lines);
<span style="color: #7f0055">for </span>(<span style="color: #005032">vector</span>&lt;<span style="color: #005032">vector</span>&lt;<span style="color: #005032">string</span>&gt; &gt;::<span style="color: #005032">iterator </span>piter = paragraph.begin(); piter
        != paragraph.end(); ++piter) {
    <span style="color: #7f0055">for </span>(<span style="color: #005032">vector</span>&lt;<span style="color: #005032">string</span>&gt;::<span style="color: #005032">iterator </span>siter = (*piter).begin(); siter
            != (*piter).end(); ++siter) {
        cout &lt;&lt; *siter &lt;&lt; ends;
    }
    cout &lt;&lt; endl;
}</pre>
<p>37、迭代器范围（P269）</p>
<p>C++定义的容器类型中，只有vector和deque容器提供下面两种重要的运算集合：迭代器算术运算，以及使用除了==和!=之外的关系操作符来比较两个迭代器（==和!=这两种关系运算适用于所有容器）。</p>
<p>list容器的迭代器既不支持算术运算（减法或加法），也不支持关系运算（&lt;=,&lt;,&gt;=,&gt;）它只提供前置和后置的自增、自减以及相同（不等）运算。</p>
<p>38、容器元素都是副本</p>
<p>在容器中添加元素时，系统是将元素值复制到容器里的。类似地，使用一段元素初始化新容器时，新容器存放的是原始元素的副本。被复制的原始值与新容器中的元素各不相关，此后容器内元素值发生变化时，被复制的原值不会受到影响，反之亦然。</p>
<p>39、下标操作和.at(n)的区别</p>
<blockquote>
<p>vector&lt;string&gt; svec; //<em>empty vector;</em></p>
<p>cout &lt;&lt; svec[0]; //<em><u>run-time error</u>:There are no elements in svec!</em></p>
<p>cout &lt;&lt; svec.at(0); //<em>throws <strong>out_of_range</strong> <u>exception</u></em></p></blockquote>
<p>40、容器的赋值（P283）</p>
<p>assign操作首先删除容器中所有的元素，然后将其参数所指定的新元素插入到该容器中。与复制容器元素的构造函数一样，如果两个容器类型相同，其元素类型也相同，就可以使用赋值操作符（=）将一个容器赋值给另一个容器。如果在不同（或相同）类型的容器内，元素类型不相同但是相互兼容，则其赋值运算必须使用assign函数。例如，可通过assign操作实现将vector容器中一段char*类型的元素赋给string类型的list容器。</p>
<p class="note">由于assign操作首先删除容器中原来存储的所有元素，因此，传递给assign函数的迭代器不能指向调用该函数的容器内的元素。</p><img src ="http://www.cppblog.com/mymsdn/aggbug/73033.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2009-02-05 03:48 <a href="http://www.cppblog.com/mymsdn/archive/2009/02/05/cpp-notes-4.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ notes (3)</title><link>http://www.cppblog.com/mymsdn/archive/2008/12/25/cpp-notes-3.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 25 Dec 2008 08:13:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2008/12/25/cpp-notes-3.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/70336.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2008/12/25/cpp-notes-3.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/70336.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/70336.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p>21、vector的动态增长优于预先分配内存。</p> <p>使用vector的时候最好动态地添加元素。它不同于C和Java或其他语言的数据类型，为了达到连续性，更有效的方法是先初始化一个空vector对象，然后再动态添加元素，而不是预先分配内存。</p> <p>22、vector值初始化</p> <p>内置-&gt;0</p> <p>有默认构造-&gt;调用默认构造</p> <p>无默认构造，有其他构造-&gt;程序员手动提供初始值</p> <p>无默认构造，也无其他构造-&gt;标准库产生一个带初值的对象</p> <p>23、数组下标的类型</p> <p>C++中，数组下标的正确类型是size_t而不是int，size_t是一个与机器相关的unsigned类型。</p> <p>24、在声明指针的时候，可以用空格将符号*与其后的标识符分隔开来，string *ps与string* ps都是可以的，但后者容易产生误解，如：</p> <p>string* ps1,ps2;&nbsp;&nbsp;&nbsp;&nbsp; //ps1是指针，而ps2是一个string对象</p> <p>也就是说，人们可能误把string和string*当作两个类型，或者说string*被当作一种新类型来看待，<u>但这是错的</u>！</p> <p>25、一个有效的指针必然是以下三种状态之一：</p> <ol> <li>保存特定的对象的地址；  <li>指向某个对象后面的另一对象；  <li>或者是0值。表明它不指向任何对象。</li></ol> <p>其中int *pi=0;与int *pi;是不同的。前者是初始化指针指向0地址的对象（即为NULL）（pi initialized to address to no object），后者却是未初始化的（ok, but dangerous, pi is uninitialized）。</p> <p>编译器可以检测出0值的指针，程序可判断该指针并未指向一个对象，而未初始化的指针的使用标准并未定义，对大多数编译器来说，如果使用未初始化的指针会将指针中存放的不确定值视为地址，然后操纵该内存地址中存放的位内容，使用未初始化的指针相当于操纵这个不确定的地址中存储的基础数据，因此对未初始化的指针进行解引用时，通常会导致程序崩溃。</p> <p>26、void*指针</p> <p>void*指针只支持几种有限的操作：</p> <ol> <li>与另一个指针进行比较；  <li>向函数传递void*指针或从函数返回void*指针；  <li>给另一个void*指针赋值。</li></ol> <p>不允许使用void*指针操纵它所指向的对象。</p> <p>27、指针和引用的比较（P105）</p> <p class="quote">虽然使用引用（reference）和指针都可间接访问另一个值，但它们之间有两个重要区别。第一个区别在于引用总是指向某个对象：定义引用时没有初始化是错误的。第二个重要区别则是赋值行为的差异：给引用赋值修改的是该引用所关联的对象的值，而并不是使引用与另一个对象关联。引用一经初始化，就始终指向同一个特定对象（这就是为什么引用必须在定义时初始化的原因）。</p> <p>28、指针与typedef（P112）</p> <p>const放在类型前和放在类型后都可以表示同样的意思：</p><pre class="gc-code"><span style="color: #0000ff">const</span> <span style="color: #0000ff">string</span> s1;
<span style="color: #0000ff">string</span> <span style="color: #0000ff">const</span> s2;</pre>
<p>s1和s2均表示常量字符串对象。</p>
<p>但因此就导致了下面的句子可能产生误解：</p><pre class="gc-code"><span style="color: #0000ff">typedef</span> <span style="color: #0000ff">string</span> *pstring;
<span style="color: #0000ff">const</span> pstring cstr;</pre>
<p>容易错把typedef当成文本扩展而产生下面的理解：</p><pre class="gc-code"><span style="color: #0000ff">const</span> <span style="color: #0000ff">string</span> *cstr; <span style="color: #008000">//这并非上面例子的正确意思！（错误）</span></pre>
<p>应该从声明的句子看，也就是说只看const pstring cstr;，在这里pstring是一种指针类型，const修饰的是这个类型，因此正确的理解应该是：</p><pre class="gc-code"><span style="color: #0000ff">string</span> *<span style="color: #0000ff">const</span> cstr;</pre>
<p>而const pstring cstr;其实可以表示为pstring const cstr;，这样的写法则不容易产生误解。从右向左阅读的意思就是：cstr是const pstring类型，即指向string对象的const指针。</p>
<p>29、创建动态数组（注意点见代码注释）</p><pre class="gc-code"><span style="color: blue">const char </span>*cp1 = <span style="color: #a31515">"some value"</span>;
<span style="color: blue">char </span>*cp2 = <span style="color: #a31515">"other value"</span>;

<span style="color: blue">int </span>*piArray1 = <span style="color: blue">new int</span>[10];    <span style="color: green">//内置类型没有初始化
</span><span style="color: blue">int </span>*piArray2 = <span style="color: blue">new int</span>[10]();    <span style="color: green">//内置类型需要加空圆括号，对数组元素进行初始化
</span>std::string *psArray1 = <span style="color: blue">new </span>std::string[10];    <span style="color: green">//默认构造函数初始化

</span>std::cout&lt;&lt;<span style="color: #a31515">"----------"</span>&lt;&lt;std::endl
    &lt;&lt;<span style="color: #a31515">"*cp1\t\t:"</span>&lt;&lt;*cp1&lt;&lt;std::endl
    &lt;&lt;<span style="color: #a31515">"*cp2\t\t:"</span>&lt;&lt;*cp2&lt;&lt;std::endl
    &lt;&lt;<span style="color: #a31515">"*piArray1\t:"</span>&lt;&lt;*piArray1&lt;&lt;std::endl
    &lt;&lt;<span style="color: #a31515">"*piArray2\t:"</span>&lt;&lt;*piArray2&lt;&lt;std::endl
    &lt;&lt;<span style="color: #a31515">"*psArray1\t:"</span>&lt;&lt;*psArray1&lt;&lt;std::endl
    &lt;&lt;<span style="color: #a31515">"----------"</span>&lt;&lt;std::endl;</pre>
<p>但是下面的结果却与概念上的不同：</p><pre class="gc-code"><span style="color: green">////Visual Studio &amp; MS VC++
//----------                   
//*cp1            :s
//*cp2            :o
//*piArray1       :-842150451
//*piArray2       :0
//*psArray1       :
//----------
////Eclipse&amp;G++
//----------
//*cp1        :s
//*cp2        :o
//*piArray1    :4064608
//*piArray2    :4064560
//*psArray1    :
//----------</span></pre>
<p>看来不同的编译器对此的定义还是有所不同，注意看*piArray2的值，按照说明应该是初始化为0，但这里却仍然表现出与*piArray1一样的值，说明并没有发生初始化。</p>
<p class="note">对于动态分配的数组，其元素只能初始化为元素类型的默认值，而不能像数组变量一样，用初始化列表为数组元素提供各不相同的初值。</p>
<p>30、const对象的动态数组</p><pre class="gc-code"><span style="color: green">//P118
//error:uninitialized const array
</span><span style="color: blue">const int </span>*pciArray1 = <span style="color: blue">new const int</span>[10];
<span style="color: green">//ok:value-initialized const array
</span><span style="color: blue">const int </span>*pciArray2 = <span style="color: blue">new const int</span>[10]();
std::cout&lt;&lt;*pciArray1&lt;&lt;std::endl;
std::cout&lt;&lt;*pciArray2&lt;&lt;std::endl;</pre>
<p>上面的示例的注释来自书中，但在VC++编译器和G++编译器下却不同，具体表现为：</p>
<ul>
<li>VC++：编译正确，第一句输出随机地址的值，第二句输出初始化的0（其中按照“标准”第一种因为未向const变量初始化，应该无法通过编译，但这里可以）</li>
<li>G++：编译错误，第一句的错误信息为“uninitialized const in `new' of `const int'”，但第二句按照标准应该输出0的，这里却输出了随机地址的值。</li></ul>
<p>看来两个编译器对这一问题的看法不太一致。</p><img src ="http://www.cppblog.com/mymsdn/aggbug/70336.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2008-12-25 16:13 <a href="http://www.cppblog.com/mymsdn/archive/2008/12/25/cpp-notes-3.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ notes (2)</title><link>http://www.cppblog.com/mymsdn/archive/2008/12/20/cpp-notes-2.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sat, 20 Dec 2008 07:50:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2008/12/20/cpp-notes-2.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/69907.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2008/12/20/cpp-notes-2.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/69907.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/69907.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style>  <p>11、枚举</p><pre class="gc-code"><span style="color: #008000">//enum</span>&nbsp;&nbsp;&nbsp;&nbsp; <br><span style="color: #0000ff">enum</span> HttpVerbs { Head, Post, Get, Delete }; <br>&nbsp;&nbsp;&nbsp; <br>HttpVerbs current_verbs = Post;&nbsp;&nbsp;&nbsp;&nbsp; <br>std::cout&lt;&lt;"<span style="color: #8b0000">Current Verbs = </span>"&lt;&lt;current_verbs&lt;&lt;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp; <br><br><br><br><br><br><br><br><br><span style="color: #008000"><br><br>//error C2440: “=”: 无法从“int”转换为“HttpVerbs”</span>&nbsp;&nbsp;&nbsp;&nbsp; <br><span style="color: #008000">//current_verbs = 3;<br></span>&nbsp;&nbsp;&nbsp;&nbsp; <br><br>current_verbs = (HttpVerbs)2;&nbsp;&nbsp;&nbsp;&nbsp; <br>std::cout&lt;&lt;"<span style="color: #8b0000">Current Verbs = </span>"&lt;&lt;current_verbs&lt;&lt;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp; <br>HttpVerbs copy_verbs = current_verbs;&nbsp;&nbsp;&nbsp;&nbsp; <br>std::cout&lt;&lt;"<span style="color: #8b0000">Copy Verbs = </span>"&lt;&lt;copy_verbs&lt;&lt;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp; <br>HttpVerbs future_verbs = (HttpVerbs)((current_verbs + 1)%<span style="color: #0000ff">sizeof</span>(HttpVerbs));&nbsp;&nbsp;&nbsp;&nbsp; <br>std::cout&lt;&lt;"<span style="color: #8b0000">Future Verbs = </span>"&lt;&lt;future_verbs&lt;&lt;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp; <br>std::cout&lt;&lt;"<span style="color: #8b0000">HttpVerbs Size![by sizeof(HttpVerbs)] = </span>"&lt;&lt;<span style="color: #0000ff">sizeof</span>(HttpVerbs)&lt;&lt;std::endl;</pre>
<p>输出：</p><pre class="gc-code">Current Verbs = 1
Current Verbs = 2
Copy Verbs = 2
Future Verbs = 3
HttpVerbs Size![by <span style="color: #0000ff">sizeof</span>(HttpVerbs)] = 4</pre>
<p>12、类，成员变量初始化</p>
<p class="quote">定义变量和定义数据成员存在着非常重要的区别：一般不能把类成员的初始化作为其定义的一部分。当定义数据成员时，只能指定该数据成员的名字和类型。类不是在类定义里定义数据成员时初始化数据成员，而是通过成为构造函数的特殊成员函数控制初始化。</p><pre class="gc-code"><span style="color: #0000ff">class</span> MyClass1
{
<span style="color: #0000ff">public</span>:<br>     <span style="color: #0000ff">int</span> GetMyValue();<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">void</span> SetMyValue(<span style="color: #0000ff">int</span> value);
<span style="color: #0000ff">private</span>:<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #008000">//error C2864: “MyClass1::myValue”: 只有静态常量整型数据成员才可以在类中初始化<br></span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff">int</span> myValue = 3;       <span style="color: #008000">//只需修改为int myValue;即可</span>
};</pre>
<p>13、struct关键字</p>
<p>C++支持另一个关键字struct，它也可以定义类类型。struct关键字是从C语言中继承过来的。</p>
<p>如果使用class关键字来定义类，那么定义在第一个访问标号前的任何成员都隐式指定为private；如果使用struct关键字，那么这些成员都是public，除非有其他特殊的声明，如添加了private才为private，否则都是public，因此没必要添加public关键字。</p>
<p class="note">用class和struct关键字定义类的唯一差别在于默认访问级别：默认情况下，struct的成员为public，而class的成员为private。</p>
<p>14、预编译头文件</p>
<p>一、<u>什么是预编译头文件? <br></u>预编译头文件物理上与通常的的.obj文件是一样的，但编译入预编译头的.h,.c,.cpp文件在整个编译过程中，只编译一次，如预编译头所涉及的部分不发生改变的话，在随后的编译过程中此部分不重新进行编译。进而大大提高编译速度，并便于对头文件进行管理，也有助于杜绝重复包含问题。</p>
<p>VC++程序一般包含的头文件都比较复杂，如果每次都逐行分析可能会花很多时间，所以VC++默认设置是第一次编译时分析所有头文件，生成.pch文件，这个文件很大，但以后每次编译时就可以节省很多时间。如果删除了这个文件，下次编译时VC++会自动生成它。</p>
<p>二、<u>什么时候使用预编译头? <br></u>当大多.c或.cpp文件都需要相同的头文件时。 <br>当某些代码被大量重复使用时。 <br>当导入某些不同库都有实现的函数，并产生混乱时。</p>
<p>15 、在头文件中必须总是使用完全限定的标准库名字。</p>
<p>因为预处理器会将头文件复制到使用它的任何地方，两种可能，一种是如果在头文件中使用using，会使相关代码不论是否需要该using都必将放置一个using，另一种是，假设有另一个库可能也包含了相应的方法如有方法std::cout以及my::cout，如果使用了using，有可能导致被引入的程序偏离原本的使用意图，或者导致编译错误。</p>
<p>16、字符串字面值和标准库string不是同一种类型</p>
<p class="quote">因为历史原因以及为了与C语言兼容，字符串字面值与标准库string类型不是同一种类型。这一点很容易引起混乱，编程时一定要注意区分字符串字面值和string数据类型的使用，这很重要。</p>
<p>17、getline函数输入的时候丢弃末尾的换行符，并将整行返回，而且不丢弃第一个换行符，也就是即便你一开始就输入了换行符，它仍然会返回，只不过返回的是一个空字符串而已。</p>
<p>编写程序实现从标准输入每次读取一行文本。然后改写程序，每次读入一个单词!</p><pre class="gc-code"><span style="color: #3f7f5f">//std::cout&lt;&lt;"getline：&lt;&lt;std::endl;
</span>WriteLine(<span style="color: #2a00ff">"getLine"</span>);
WriteLine(<span style="color: #2a00ff">"P72 编</span>);
<span style="color: #7f0055">using </span>std::string;

WriteLine(<span style="color: #2a00ff">"每(输"NEXT\"进"</span>);
<span style="color: #005032">string </span>str;
<span style="color: #7f0055">while</span>(std::getline(std::cin, str))
{
    <span style="color: #7f0055">if</span>(str == <span style="color: #2a00ff">"NEXT"</span>)
        <span style="color: #7f0055">break</span>;
    std::cout&lt;&lt;str&lt;&lt;std::endl;
}

WriteLine(<span style="color: #2a00ff">"每输"NEXT\"进"</span>);
<span style="color: #7f0055">while</span>(std::getline(std::cin, str))
{
    <span style="color: #7f0055">if</span>(str == <span style="color: #2a00ff">"NEXT"</span>)
        <span style="color: #7f0055">break</span>;
    <span style="color: #008000">//从第0个开始查找空白</span><br>    <span style="color: #7f0055">static const </span>std::<span style="color: #005032">basic_string</span>&lt;<span style="color: #7f0055">char</span>&gt;::<span style="color: #005032">size_type </span>npos = (std::<span style="color: #005032">basic_string</span>&lt;<span style="color: #7f0055">char</span>&gt;::<span style="color: #005032">size_type</span>)-1;
    std::<span style="color: #005032">basic_string</span>&lt;<span style="color: #7f0055">char</span>&gt;::<span style="color: #005032">size_type </span>firstIndexOfEmpty = str.find_first_of(<span style="color: #2a00ff">" "</span>, 0);
    <span style="color: #7f0055">if</span>(firstIndexOfEmpty != npos)
        std::cout&lt;&lt;str.substr(0, firstIndexOfEmpty)&lt;&lt;std::endl;
    <span style="color: #7f0055">else
        </span>std::cout&lt;&lt;str&lt;&lt;endl;
}</pre>
<p>其中WriteLine函数：</p><pre class="gc-code"><span style="color: #7f0055">void </span>WriteLine(std::<span style="color: #005032">string </span>str)
{
    std::cout&lt;&lt;str&lt;&lt;std::endl;
}</pre><a href="http://11011.net/software/vspaste"></a>
<p>18、std::string对象的加法</p>
<p>如果一串字符串和string对象混合相加，则要求+操作符左右操作数必须至少有一个是string类型的。</p>
<p>推论：一串字符串和string对象混合相加，前两个操作数中至少有一个是string对象。</p><pre class="gc-code">std::<span style="color: #005032">string </span>str2 = str1 + <span style="color: #2a00ff">"this" </span>+ <span style="color: #2a00ff">" that" </span>+ <span style="color: #2a00ff">" those"</span>;
std::cout &lt;&lt; str2 &lt;&lt; std::endl;
<span style="color: #3f7f5f">//error C2110: “+”: 不能添加两个指针<br></span>std::<span style="color: #005032">string </span>str3 = <span style="color: #2a00ff">"this" </span>+ <span style="color: #2a00ff">" that" </span>+ str1 + <span style="color: #2a00ff">" those"</span>;
std::cout &lt;&lt; str3 &lt;&lt; std::endl;</pre><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a>
<p>19、C标准库头文件和C++版本</p>
<p>C++标准库也包括C标准库，命名上则在C标准库的名字前加一个c并省去后缀.h，比如C标准库中的ctype.h，在C++中就有相应的标准库cctype（注意没有.h）。C++和C标准库文件的内容是一样的，只是采用了更适合C++的形式。而且通常cname头文件中定义的名字都定义在命名空间std内，而.h版本的名字却不是这样。</p>
<p>20、关于中文编码的相关问题</p>
<p>我们知道大部分的编译器以及解决方案都由外国人发明创造，特别是美国人。因此很多程序默认不支持中文。虽然随着Unicode的普及这部分问题得到了很大的改善（比如C#就可以完美地支持中文），但是类似C++这样的语言，仍然面临着中文编码的问题。关于编码，有一篇值得推荐的文章：<a target="_blank" href="http://eeee6688.blogspot.com/2008/12/vcc.html">地址1</a>（<a target="_blank" href="http://blog.csdn.net/fishinthewind/archive/2007/05/15/1610715.aspx">备用地址</a>）<a target="_blank" href="http://6qfhba.bay.livefilestore.com/y1pfqVRUn0vZKY06fbosctrFvRsDf6f3IUue9jMo5mSc5CZRVjO_1UWlRHl8EfJgacynRm-3eK2cn4/VC%2B%2B%E7%9A%84%E4%B8%AD%E6%96%87%E5%AD%97%E7%AC%A6%E5%A4%84%E7%90%86%E6%96%B9%E5%BC%8F.docx">下载后打印</a>（docx，50.7KB）<a target="_blank" href="http://cnweb.search.live.com/results.aspx?q=C%2B%2B+%E4%B8%AD%E6%96%87%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81+Unicode+GB2312&amp;form=QBRE">查找更多</a></p><img src ="http://www.cppblog.com/mymsdn/aggbug/69907.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2008-12-20 15:50 <a href="http://www.cppblog.com/mymsdn/archive/2008/12/20/cpp-notes-2.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ notes (1)</title><link>http://www.cppblog.com/mymsdn/archive/2008/12/19/cpp-notes-1.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 19 Dec 2008 09:52:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2008/12/19/cpp-notes-1.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/69853.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2008/12/19/cpp-notes-1.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/69853.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/69853.html</trackback:ping><description><![CDATA[<!--mymsdn style!-->
<link rel="stylesheet" type="text/css" href="http://files.cnblogs.com/volnet/gocool.css"> <style type="text/css">
body{background-color:#eeeeee;}
</style> 1、标识符命名规则！
<p class="quote">标识符不能包含两个连续的下划线，也不能以下划线开头后面紧跟一个大写字母。有些标识符（在函数外定义的标识符）不能以下划线开头。</p>
<p>但是在G++编译器和VC编译器下，二者均可正确编译！</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/C_FB3C/image_4.png"><img style="border-width: 0px; display: inline;" title="Eclipse&amp;G++" alt="Eclipse&amp;G++" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/C_FB3C/image_thumb_1.png" border="0" height="344" width="454"></a><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/C_FB3C/image_6.png"><img style="border-width: 0px; display: inline;" title="Visual studio 2008" alt="Visual studio 2008" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/C_FB3C/image_thumb_2.png" border="0" height="277" width="378"></a></p>
<p>2、跨平台编译程序！</p>
<p>这里不是要讲解如何跨平台编译程序，也不是告诉你如何更好地编写通用平台的程序规则，那可能涉及到很多的宏定义以及硬件相关特性。这里仅为使用示例代码提供一种精简的方式。</p>
<p>用Eclipse+MinGW的方式默认会很精简，所以把它当作一种目标！</p>
<p>用Visual Studio 2008创建的程序会让你引入预编译头stdafx.h（这通常发生在使用Visual Studio创建Win32控制台应用程序，并直接点击&#8220;完成&#8221;后），这将导致你无法将在Eclipse上编写的程序直接运行在Visual Studio上。这时你应该通过修改项目属性来获得这种精简的方式：（选择项目，右键属性，选择配置属性-&gt;C/C++-&gt;预编译头-&gt;创建/使用预编译头，选择&#8220;不使用预编译头&#8221;-&gt;&#8220;确定&#8221;后再次编译即可！）</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/C_FB3C/image_10.png"><img style="border-width: 0px; display: inline;" title="properties" alt="properties" src="http://www.cppblog.com/images/cppblog_com/mymsdn/WindowsLiveWriter/C_FB3C/image_thumb_4.png" border="0" height="295" width="752"></a> </p>
<p>3、变量命名习题</p>
<pre class="gc-code"><span style="color: green;">//测试变量命名！
//error C2632: &#8220;int&#8221;后面的&#8220;double&#8221;非法
//int double = 3.14159;
//-------------------------------------------------
</span><span style="color: blue;">char </span>_=<span style="color: #a31515;">'a'</span>;
std::cout&lt;&lt;_&lt;&lt;std::endl;
<span style="color: green;">//-------------------------------------------------
//warning C4091: &#8220;&#8221;: 没有声明变量时忽略&#8220;bool&#8221;的左侧
//error C2059: 语法错误: &#8220;-&#8221;
//bool catch-22;
//-------------------------------------------------
//error C2059: 语法错误: &#8220;数字上的错误后缀&#8221;
//char 1_or_2 = '1';
//-------------------------------------------------
</span><span style="color: blue;">float </span>Float=3.14f;
std::cout&lt;&lt;Float&lt;&lt;std::endl;</pre>
<p>4、在C++中，&#8220;初始化不是赋值&#8221;</p>
<p>初始化指创建变量并给它赋初始值，而赋值则是擦除对象的当前值并用新值代替。</p>
<div class="gc-code">
<pre><span style="color: #0000ff;">int</span> ival(1024); <span style="color: #008000;">//直接初始化</span>
<span style="color: #0000ff;">int</span> ival = 1024; <span style="color: #008000;">//复制初始化</span></pre>
</div>
<p>直接初始化语法更灵活，效率更高！</p>
<p>对内置类型来说，复制初始化和直接初始化几乎没有差别。</p>
<p>对类类型来说，有些初始化仅能用直接初始化完成。要想理解其中缘由，需要初步了解类是如何控制初始化的。</p>
<p>例如：</p>
<p>也可以通过一个计数器和一个字符初始化string对象。这样创建的对象包含重复多次的指定字符，重复次数由计数器指定：</p>
<p>std::string all_nines(10, &#8216;9&#8217;); //all_nines = &#8220;9999999999&#8221;;</p>
<p>本例中，初始化all_nines的唯一方法是直接初始化。有多个初始化式时不能使用复制初始化。（V注：这里的初始化式即为构造函数的多个重载；这里所谓的&#8220;不能使用&#8221;应该是&#8220;功能有所不及&#8221;的意思！）</p>
<p>5、变量初始化规则</p>
<p>使用未初始化的变量经常导致错误，而且十分隐蔽。问题出在未初始化的变量事实上都有一个值。编译器把该变量放到内存中的某个位置，而把这个位置的无论哪种位模式都当成是变量初始的状态。当被解释成整型值时，任何位模式都是合法的值——虽然这个值不可能是程序员想要的。因为这个值合法，所以使用它也不可能导致程序崩溃。可能的结果是导致程序错误执行和/或错误计算。</p>
<div class="gc-code">
<pre><span style="color: #008000;">//在Eclipse中运行没有出现错误！</span>
<span style="color: #008000;">//在Visual Studio中运行出现运行时错误！</span>
<span style="color: #0000ff;">int</span> ival;&nbsp;&nbsp;&nbsp; <span style="color: #008000;">//没有初始化！</span>
std::cout&lt;&lt;ival&lt;&lt;std::endl;</pre>
</div>
<p>6、声明和定义</p>
<p>为了能让多个文件访问相同的变量，C++区分了声明和定义。简单地说就是可以用extern关键字来声明，任何有分配内存行为的声明都是定义。定义也是声明。声明：标明变量的类型和名字；定义：为变量分配存储空间，还可以为变量指定初始值。</p>
<p>举例说明：</p>
<div class="gc-code">
<pre><span style="color: #0000ff;">extern</span> <span style="color: #0000ff;">double</span> pi; <span style="color: #008000;">//声明</span>
<span style="color: #0000ff;">double</span> pi; <span style="color: #008000;">//定义，声明了pi同时定义了pi</span>
<span style="color: #0000ff;">extern</span> <span style="color: #0000ff;">double</span> pi = 3.14159; <span style="color: #008000;">//定义，因为它为pi分配了初值。只有当该extern语句<br>&nbsp;&nbsp;&nbsp;&nbsp; 位于函数外部的时候才允许使用初始化式，否则将导致编译错误。</span></pre>
</div>
<p>7、变量的隐藏：</p>
<pre class="gc-code">std::<span style="color: #005032;">string </span>s1 = <span style="color: #2a00ff;">"I am a std::string!"</span>;
std::cout&lt;&lt;s1&lt;&lt;std::endl;
<span style="color: #7f0055;">for</span>(<span style="color: #7f0055;">int </span>s1=3; s1!=0; --s1)
std::cout&lt;&lt;<span style="color: #2a00ff;">"I am a number(int):"</span>&lt;&lt;s1&lt;&lt;std::endl;</pre>
<p class="note">提示：在Visual Studio 2008中使用std::string定义一个变量，再通过std::cout将其输出，将会得到&#8220;error C2679: 二进制&#8220;&lt;&lt;&#8221;: 没有找到接受&#8220;std::string&#8221;类型的右操作数的运算符(或没有可接受的转换)&#8221;错误信息，这时要检查头文件中是否包含#include &lt;string&gt;。而在Eclipse中则不用如此设置（具体看编译器版本）。这与标准库实现的具体细节有关，在MSVC中，它在文件Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\string中被实现，在GNU中，它在base_string.h中被实现。在使用std::string时，总是包含#include &lt;string&gt;是一个好习惯！</p>
<p>8、const对象默认为文件的局部变量</p>
<p>一般声明变量后可以在其它文件中通过extern关键字声明并使用该变量：</p>
<pre class="gc-code"><span style="color: #008000;">//文件1：</span>
<span style="color: #0000ff;">int</span> counter;
<span style="color: #008000;">//文件2：</span>
<span style="color: #0000ff;">extern</span> <span style="color: #0000ff;">int</span> counter;
++counter;</pre>
<p>但是如果是const则无法访问。可以通过显式指定extern关键字使其成为全局可访问对象：</p>
<pre class="gc-code"><span style="color: #008000;">//文件1：</span>
<span style="color: #0000ff;">extern</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> bufSize = getBufSize();
<span style="color: #008000;">//文件2：</span>
<span style="color: #0000ff;">extern</span> count <span style="color: #0000ff;">int</span> bufSize;
<span style="color: #008000;">//&#8230;&#8230;使用bufSize</span></pre>
<p class="note">注解：非const变量默认为extern。要使const变量能够在其他的文件中访问，必须显式地指定它为extern。</p>
<p>9、引用</p>
<pre class="gc-code"><span style="color: #0000ff;">int</span> ival = 1024;
<span style="color: #0000ff;">int</span> &amp;refVal = ival;</pre>
<p class="quote">当引用初始化后，只要该引用存在，就保持绑定到初始化时指向的对象。不可能将引用绑定到另一个对象。</p>
<p>也正因为如此，所以引用比指针的优势就在于：引用不可以在方法中篡改，这使得方法变量变得安全了。</p>
<p>10、const引用</p>
<pre class="gc-code"><u><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span></u> ival = 1024;
<u><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span></u> &amp;refVal = ival;</pre>
<p>这里我们要求左侧的类型是一致的，包括const！</p>
<p class="quote">非const引用只能绑定到与该引用同类型的对象。<br>const引用则可以绑定到不同但相关的类型的对象或绑定到右值。（具体示例详见C++Primer v4 P52）</p>
<p>例如：</p>
<div class="quote">
<pre class="gc-code"><span style="color: #008000;">//错误代码</span>
<span style="color: #0000ff;">double</span> dval = 3.14;
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> &amp;ri = dval;</pre>
<p>编译器会将这些代码转换成如以下形式的编码：</p>
<pre class="gc-code"><span style="color: #0000ff;">int</span> temp = dval;
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> &amp;ri = temp;</pre>
如果ri不是const，那么可以给ri赋一新值。这样做不会修改dval，而是修改了temp。期望对ri的赋值会修改dval的程序员会发现dval并没有被修改。仅允许const引用绑定到需要临时使用的值完全避免了这个问题，因为const引用是只读的。<br>&nbsp;</div>
<p>但是如下代码可以执行：</p>
<pre class="gc-code"><span style="color: #7f0055;">int </span>ival = 1024;
<span style="color: #7f0055;">const int </span>&amp;refVal = ival;
++ival;
<span style="color: #3f7f5f;">//++refVal;    //error C3892: &#8220;refVal&#8221; 不能给常量赋值
</span>std::cout&lt;&lt;<span style="color: #2a00ff;">"ival="</span>&lt;&lt;ival&lt;&lt;<span style="color: #2a00ff;">"\trefVal="</span>&lt;&lt;refVal&lt;&lt;std::endl;</pre>
<p>输出：ival=1025&nbsp;&nbsp;&nbsp; refVal=1025</p>
<pre class="gc-code"><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">double</span> dval = 3.14;
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> &amp;ri = (<span style="color: #0000ff;">int</span>)dval;
std::cout&lt;&lt;ri&lt;&lt;std::endl;</pre>
输出：3  <img src ="http://www.cppblog.com/mymsdn/aggbug/69853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2008-12-19 17:52 <a href="http://www.cppblog.com/mymsdn/archive/2008/12/19/cpp-notes-1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[学习笔记]C++ Primer[第二章]基本语言</title><link>http://www.cppblog.com/mymsdn/archive/2007/06/16/26420.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 15 Jun 2007 17:32:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2007/06/16/26420.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/26420.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2007/06/16/26420.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/26420.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/26420.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;30&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">算术类型的存储空间依机器而定。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;30&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">表示整数、字符和布尔值的算术类型合称为<strong>整形(integral type)</strong><br>字符类型有两种：char和wchar_t。char类型通常是单个机器字节(byte)。wchar_t类型用于扩展字符集，比如汉字和日语</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;31&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">在位这一级上，存储器是没有结构和意义的。<br>让存储具有结构的最基本方法是用块（chunk）处理存储。……虽然确切的大小因机器不同而不同，但是通常将8位的块作为一个字节，32位或4个字节作为一个“字（word）”</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;32&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">C++标准并未定义signed类型如何用位来表示，而是由每个编译器自由决定如何表示signed类型。……符号位为1，值就为负数；符号位为0，值就为0或正数。……有些语言中将负数赋给unsigned类型是非法的，但在C++中这是合法的。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;35&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">为了兼容C语言，C++中所有的字符串字面值都由编译器自动在末尾添加一个空字符。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;36&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">两个相邻的仅由空格、制表符或换行符分开的字符串字面值（或宽字符串字面值），可连接成一个新字符串字面值。<br>//concatenated long string literal<br>std::cout&lt;&lt;"a multi-line "<br>"string literal "<br>"using concatenation "<br>&lt;&lt;std::endl;<br>执行这条语句将会输出：<br>a multi-line string literal using concatenation<br>如果连接字符串字面值和宽字符串字面值，将会出现什么结果呢？例如：<br>//Concatenating plain and wide character strings is undefined<br>std::cout&lt;&lt;"multi-line" L"literal "&lt;&lt;std::endl;<br>其结果未定义的（unsigned），也就是说，连接不同类型的行为标准没有定义。这个程序可能会执行，也可能会崩溃或者产生没有用的值，而且在不同的编译器下程序的动作可能不同。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;36&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">在一行的末尾加一反斜线符号可将此行和下一行当作同一行处理。<br>std::cou\<br>t&lt;&lt;"Hi"&lt;&lt;st\<br>d::endl;<br>等价于<br>std::cout&lt;&lt;"Hi"&lt;&lt;std::endl;<br>注意反斜线符号必须是该行的尾字符——不允许其后面有注释或空格。同样，后继行行首的任何空格和制表符都是字符串字面值的一部分。正因如此，长字符串字面值的后继行才不会有正常的缩进。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;39&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">C++是一门静态类型语言，在编译时会作类型检查。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;41&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">标识符不能包含两个连续的下划线，也不能以下划线开头后面紧跟一个大写字母。有些标识符（在函数外定义的标识符）不能以下划线开头。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;42&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">C++支持两种初始化变量的形式：复制初始化（copy-initialization）和直接初始化（direct-initialization）。复制初始化语法用等号（=），直接初始化则是把初始化式放在括号中：<br>int ival(1024);&nbsp;&nbsp;&nbsp; //direct-initialization<br>int ival = 1024;&nbsp;&nbsp;&nbsp; //copy-initialization</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;43&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">也可以通过一个计数器和一个字符初始化string对象。这样创建的对象包含重复多次的指定字符，重复次数由计数器指定：<br>std::string all_nines(10,'9');&nbsp;&nbsp;&nbsp; //all_nines="9999999999"<br>本例中，初始化all_nines的唯一方法是直接初始化。有多个初始化式时不能使用复制初始化</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;44&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">内置类型变量是否自动初始化取决于变量定义的位置。在函数体外定义的变量都初始化成0，在函数体里定义的内置类型变量不进行自动初始化。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;46&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">extern声明不是定义，也不分配存储空间。<br>……<br>只有当extern声明位于函数外部时，才可以含有初始化式。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;50&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">非const变量默认为extern，要使const变量能够在其他的文件中访问，必须显式地指定它为extern</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;51&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">引用只是对象的另一个名字</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;52&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">const引用可以初始化为不同类型的对象或者初始化为右值<br>……<br>非const引用只能绑定到与该引用同类型的对象。<br>const引用则可以绑定到不同但相关的类型的对象或绑定到右值。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;56-57&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">如果使用class关键字来定义类，那么定义在第一个访问标号前的任何成员都隐式指定为private；如果使用struct关键字，那么这些成员都是public。使用class还是struct关键字来定义类，仅仅影响默认的初始化访问级别。<br>可以等效地定义Sales_item类为：<br>struct Sales_item{<br>&nbsp;&nbsp;&nbsp; //no need for public label, memebers are public by default<br>&nbsp;&nbsp;&nbsp; //operations on Sales_item objects<br>private:<br>&nbsp;&nbsp;&nbsp; std::string isbn;<br>&nbsp;&nbsp;&nbsp; unsigned units_sold;<br>&nbsp;&nbsp;&nbsp; double revenues<br>};<br>本例的类定义和前面的类定义只有两个区别：这里使用了关键字struct，并且没有在花括号后使用关键字public。struct的成员都是public，除非有其他特殊的声明，所以就没有必要添加public标号。<br>用class和struct关键字定义类的唯一差别在于默认访问级别：默认情况下，struct的成员为public，而class的成员为private。</td></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="495" border="0" unselectable="on"> <tbody> <tr> <td style="font-size: 9pt" valign="top" width="493" bgcolor="#cccccc">Page&nbsp;59&nbsp;( Chapter 2 基本语言)</td></tr> <tr> <td style="font-size: 9pt" valign="top" width="493">这种行为有一个很重要的含义：当我们在头文件中定义了const变量后，每个包含该头文件的源文件都有了自己的const变量，其名称和值都一样。</td></tr></tbody></table><img src ="http://www.cppblog.com/mymsdn/aggbug/26420.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2007-06-16 01:32 <a href="http://www.cppblog.com/mymsdn/archive/2007/06/16/26420.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[学习笔记]C++ Primer[第一章]快速入门</title><link>http://www.cppblog.com/mymsdn/archive/2007/06/09/25908.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sat, 09 Jun 2007 09:29:00 GMT</pubDate><guid>http://www.cppblog.com/mymsdn/archive/2007/06/09/25908.html</guid><wfw:comment>http://www.cppblog.com/mymsdn/comments/25908.html</wfw:comment><comments>http://www.cppblog.com/mymsdn/archive/2007/06/09/25908.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/mymsdn/comments/commentRss/25908.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mymsdn/services/trackbacks/25908.html</trackback:ping><description><![CDATA[<p>[目的]</p>
<p>记录C++ Primer学习中遇到的需要记忆的东西，这里仅以我个人为标准进行记录。</p>
<p>[格式]</p>
<p>以下样例代表了本文所描述的所有摘要片段将通过以下模版进行创建。</p>
<table cellSpacing=0 cellPadding=2 width=495 border=0 unselectable="on">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493 bgColor=#cccccc>Page&nbsp;[PageIndex]&nbsp;( Chapter&nbsp;[ChapterIndex] [Title of Chapter])</td>
        </tr>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493>[正文]</td>
        </tr>
    </tbody>
</table>
<p>[正文]</p>
<table cellSpacing=0 cellPadding=2 width=495 border=0 unselectable="on">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493 bgColor=#cccccc>Page 3&nbsp;( Chapter 1 快速入门)</td>
        </tr>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在大多数系统中，main函数的返回值是一个状态指示器。返回值0往往表示main函数成功执行完毕。任何其他非零的返回值都有操作系统定义的含义。通常非零返回值表明有错误出现。每一种操作系统都有自己的方式告诉用户main函数返回什么内容。</td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=2 width=495 border=0 unselectable="on">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493 bgColor=#cccccc>Page 3&nbsp;( Chapter 1 快速入门)</td>
        </tr>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493>
            <p>在书中提到的<br>C:\directory&gt; cl -GX prog1.cpp<br>命令在利用VS2005所带的32位C/C++优化编译器下会出现如下提示：
            <p><strong>用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 14.00.50727.762 版<br>版权所有(C) Microsoft Corporation。保留所有权利。 </strong>
            <p><strong>cl: 命令行 warning D9035 :&#8220;GX&#8221;选项已否决，并将在将来的版本中移除<br>cl: 命令行 warning D9036 :使用&#8220;EHsc&#8221;而不使用&#8220;GX&#8221;</strong></p>
            </td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=2 width=495 border=0 unselectable="on">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493 bgColor=#cccccc>Page&nbsp;5&nbsp;( Chapter 1 快速入门)</td>
        </tr>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493>并没有直接定义进行输入或输出（IO）的任何语句，这种功能是由标准库提供的。</td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=2 width=495 border=0 unselectable="on">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493 bgColor=#cccccc>Page&nbsp;6&nbsp;( Chapter 1 快速入门)</td>
        </tr>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493>std::cout&lt;&lt;"Enter two number:"&lt;&lt;std::endl;<br>每个输出操作符实例都接受两个操作数：左操作数必须是ostream对象；右操作数是要输出的值。操作符将其右操作数写到作为其左操作数的ostream对象。<br>（std::cin与std::cout相反：<br>std::cout 左&#8592;右（注意箭头方向）<br>std::cin 左&#8594;右（注意箭头方向））<br>&#8230;&#8230;<br>endl是一个特殊之，称为<strong>操纵符</strong>（manipulator），将它写入输出流时，具有输出换行的效果，并刷新与设备相关联的缓冲区（buffer）。通过刷新缓冲区，用户可立即看到写入到流中的输出。</td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=2 width=495 border=0 unselectable="on">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493 bgColor=#cccccc>Page&nbsp;16&nbsp;( Chapter 1 快速入门)</td>
        </tr>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493>当我们使用istream对象作为条件，结果是测试流的状态。如果流是有效的（也就是说，如果读入下一个输入是可能的）那么测试成功。遇到文件结束符（end-of-file）或遇到无效输入时，如读取了一个不是整数的值，则istream对象是无效的。处于无效状态的istream对象将导致条件失败。<br>【本信息针对上文中】<br>int sum = 0,value;<br>while(std::cin&gt;&gt;value)&nbsp;&nbsp; //以前很少在while里面使用这样的输入<br>&#8230;&#8230;</td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=2 width=495 border=0 unselectable="on">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493 bgColor=#cccccc>Page&nbsp;20&nbsp;( Chapter 1 快速入门)</td>
        </tr>
        <tr>
            <td style="FONT-SIZE: 9pt" vAlign=top width=493>点操作符通过它的左操作数取得有操作数。点操作符仅应用于类类型的对象：左操作数必须是类类型的对象，右操作数必须指定该类型的成员。 </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/mymsdn/aggbug/25908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mymsdn/" target="_blank">volnet</a> 2007-06-09 17:29 <a href="http://www.cppblog.com/mymsdn/archive/2007/06/09/25908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>