??xml version="1.0" encoding="utf-8" standalone="yes"?> 在C++中我们应该少用指针,多用引用Q原因请大家自行搜烦。在传递数l的时候我们需要格外注意,先让我们看一个简单的范例?/p> 首先q个范例无法~译通过Q?/p>
原因出在类型推断上。根据定义,Func2的类型必LT&Q也是说传递实参的时候,两个形参必须是相同的Q而这一点在模板~程中就会由~译器来负责推断?/p>
Func1Q?/p>
调用Func1(a, b)则推断的cd分别是Func1(int*, int*)Q调用函数将会自动将数组的首地址指针作ؓ实参q行传递,因此cd推断两Ş参相同,~译通过Q?/p>
Func2Q?/p>
调用Func2(a, b)因ؓ我们希望按引用的方式q行实参传递,因此需要遵循这L规律Q?/p>
QP208Q如果Ş参是数组的引用,~译器将不会数l实参{化ؓ指针Q而是传递数l引用的本n。在q种情况下,数组大小成ؓ形参和实参类型的一部分?/p>
所以推断类型分别是Func2(int (&)[10], int (&)[12])Q因为int (&)[10] != int (&)[12]Q所以与T == T相?zhn)Q自然也q译不q了Q?/p>
Func3Q?/p>
该函数是Func2的一个静态表C,通过上面的解释应该很Ҏ(gu)理解q个代码了?/p> 51、static成员函数 因ؓstatic成员不是M对象的组成部分,所以static成员函数不能被声明ؓconst。毕竟,成员函数声明ؓconst是承诺不会修改该函数所属的对象。最后,static成员函数也不能被声明函数?/p> 52、特D的整型const static成员QP401Q?/p> const static数据成员在类的定义体中初始化Ӟ该数据成员仍必须在类的定义体之外q行定义?/p> class Accout{ public: static double rate() { return interestRate;} static void rate(double); //sets a new rate private: static const int period = 30; //interest posted every 30 days double daily_tbl[period]; // ok: period is constant expression } //definition of static member with no initializer; //the initial value is specified inside the class definition const int Accout::period; 但在gcc和MS vc++~译器下g均不需要再ơ定义,也就是题讄“必须”二字在此失效?/p> 53、操作符重蝲QP435Q?/p> 下面是一些指导原则,有助于决定将操作W设|ؓcL员还是普通非成员函数 54、区别操作符的前~和后~形式QP447Q?/p> 同时定义前缀式操作符和后~式操作符存在一个问题:它们的Ş参数目和cd相同Q普通重载不能区别所定义的是前缀式操作符q是后缀式操作符?/p> 册一问题Q后~式操作符函数接受一个额外的Q即Q无用的Qint型Ş参。用后~操作W时Q编译器提供0作ؓq个形参的实参。尽我们的前缀式操作符函数可以使用q个额外的Ş参,但通常不应该这样做。那个Ş参不是后~式操作符的正常工作所需要的Q它的唯一目的是后缀函数与前~函数区别开来?/p> 55、显式调用前~式操作符 CheckedPtr parr(ia, ia+size); //ia points to an array of ints parr.operator(0); //call postfix operator++ parr.operator(); //call prefix operator++ 56、函数对象(P450Q?/p> struct absInt { int operator() (int val){ return val<0 ? –val : val; } }; int i = –42; absInt absObj; //object that defines function call operator unsigned int ui = absObj(i); //calls absInt::operator(int) 管absObj是一个对象而不是函敎ͼ我们仍然可以“调用”该对象,效果是运行由absObj对象定义的重载调用操作符Q该操作W接受一个int值ƈq回它的l对倹{?/p> 函数对象l常用作通用法的实参。(详见P450Q?/p> 57、函数对象的函数适配器(P453Q?/p> 标准库提供了一l函数适配器(function adapterQ,用于特化和扩展一元和二元函数对象。函数适配器分为如下两c: Q?Q绑定器QbinderQ,是一U函数适配器,它通过一个操作数l定到给定D将二元函数对象转换Z元函数对象。(bind1st?a >bind2nd 更多Q?/p> Q?Q求反器QnegatorQ,是一U函数适配器,它将谓词函数对象的真值求反。(not1?a target="_blank">not2 更多Q?/p> 58、{换操作符QP455Q?/p> 转换Z么有用?Q详见P454Q?/p> 转换函数采用如下通用形式Q?/p> operator type(); q里Qtype表示内置cd名、类cd名或q型别名所定义的名字。对M可作为函数返回类型的cdQ除了void之外Q都可以定义转换函数。一般而言Q不允许转换为数l或函数cdQ{换ؓ指针Q数据或函数指针Q以及引用类型是可以的?/p> 转换函数必须是成员函敎ͼ不能指定q回cdQƈ且Ş参表必须为空?/p> 转换函数一般不应该改变被{换的对象。因此,转换操作W通常应定义ؓconst成员?/p> 59、只能应用一个类cd转换 cȝ型{换之后不能再跟另一个类cd转换。如果需要多个类cd转换Q则代码出错?/p> 假设有Integral=>SmallInt=>intQ但是如果有一个函数cal(int)Q那么对于SmallInt siQ可以用cal(si)Q但对于Integral intVal;则不能用cal(intVal)。语a只允怸ơ类cd转换Q所以该调用出错?/p> 60、virtual与其他成员函敎ͼP479Q?/p> C++中的函数调用默认不用动态绑定。要触发动态绑定,必须满两个条gQ第一Q只有指定ؓ虚函数的成员函数才能q行动态绑定,成员函数默认为非虚函敎ͼ非虚函数不进行动态绑定;W二Q必通过基类cd的引用或指针q行函数调用?/p> 基类cd引用和指针的关键点在于静态类型(static typeQ在~译时可知的引用cd或指针类型)和动态类型(dynamic typeQ指针或引用所l定的对象的cdQ这是仅在运行时可知的)可能不同?/p> 41、vector、list、deque的性能初窥 用事实说话最有说服力Q?/p> 可以看出大致旉比例?/19/12。虽然不以佐证它们的性能差距Q但vector的常用似乎有了更充分的理由?/p>
q里使用了一个简单的旉函数大致如下Q?/p> 42、容器自增长QP286Q?/p>
每种实现都要求遵循以下原则:保push_back操作高效地在vector中添加元素。从技术上来说Q在原来为空的vector容器上nơ调用push_back函数Q从而创建拥有n个元素的vector容器Q其执行旉永远不能过n的常量倍?/p>
43、类定义中ؓ何不能具有自w的数据成员QP375Q?/p>
因ؓ只有当类定义体完成后才能定义c,因此cM能具有自w类型的数据成员。然而,只要cd一出现可以认cd声明。因此,cȝ数据成员可以是指向自w类型的指针或引用: class LinkScreen { Screen window; LinkScreen *next; LinkScreen *prev; }; 44、两U引用类cd的方法(P376Q?/p>
Sales_item item1; //default initialized object of type Sales_item class Sales_item item1; //equivalent definition of item1 两种引用cȝ型的Ҏ(gu)是等L。第二种Ҏ(gu)是从Cl承而来的,在C++中仍然有效。第一U更为简l,由C++语言引入Q得类cd更容易用?/p>
45、ؓ什么类的定义以分号l束QP376Q?/p>
分号是必ȝQ因为在cd义之后可以接一个对象定义列表。定义必M分号l束Q?/p>
class Sales_item {/* … */}; class Sales_item {/* … */} accum, trans; 46、Ş参表和函C处于cM用域中,函数q回cd不一定在cM用域?/p>
在定义于cd部的成员函数中,形参表和成员函数体都出现在成员名之后。这些都是在cM用域中定义,所以可以不用限定而引用其他成员。因为Ş参表是在ScreencM用域内,所以不必知名我们想要的是Screen::index?/p>
如果q回cd使用q定义的类型,则必M用完全限定名?/p> 47、构造函数初始化式(P387Q?/p>
与Q意的成员函数一P构造函数可以定义在cȝ内部或外部。构造函数初始化式只在构造函数的定义中而不是声明中指定?/p>
构造函数初始化列表难以理解的一个原因在于,省略初始化列表ƈ在构造函数的函数体内Ҏ(gu)据成员赋值是合法的?/p>
在构造函数初始化列表中没有显式提及的每个成员Q用与初始化变量相同的规则来进行初始化。运行该cd的默认构造函敎ͼ来初始化cȝ型的数据成员。内|或复合cd的成员的初始g赖于对象的作用域Q在局部作用域中这些成员不被初始化Q而在全局作用域中它们被初始化??/p>
如果那个cL有默认构造函敎ͼ则编译器试使用默认构造函数将会失败。在q种情况下,Z初始化数据成员,必须提供初始化式?/p>
对于q样的成员,在构造函数函C中对它们赋g起作用。没有默认构造函数的cȝ型成员,以及const或引用类型的成员Q不是哪种cdQ都必须在构造函数初始化列表中进行初始化?/p>
因ؓ内置cd的成员不q行隐式初始化,所以对q些成员是进行初始化q是赋g乎都无关紧要。除了两个例外,寚wcȝ型的数据成员q行赋值或使用初始化式在结果和性能上都是等L?/p>
48、成员初始化的次?/p>
构造函数初始化列表仅指定用于初始化成员的|q不指定q些初始化执行的ơ序。成员被初始化的ơ序是定义成员的次序?/p>
class X{ int i; int j; public: //run-time error: i is initialized before j X(int val): j(val), i(j) {} } 在这U情况下Q构造函数初始化列表看v来似乎是用val初始化jQ然后再用j来初始化i。然而i首先被初始化。这个初始化列表的效果是用尚未初始化的j值来初始化iQ?/p>
49、用默认构造函敎ͼP393Q?/p>
常犯的一个错误是采用以下方式声明一个用默认构造函数初始化的对象: Sales_item myobj(); Sales_item myobj(); //ok: but defines a function, not an object if(myobj.same_isbn(Primer_3rd_ed)) // error: myobj is a function 正确的方式应该是L相应的括P Sales_item myobj; 或?/p>
Sales_item myobj = Sales_item(); 50、显式或隐式初始?/p> 因ؓh以std::string为Ş参的构造函敎ͼ因此在调用需要MyClass对象的same_object成员函数Ӟ会自动隐式调用该构造函数构建MyClass对象Q用于操作。但生成的MyClass对象是时对象,在same_object函数调用完成后销毁。如果ؓ了避免生隐式{换可以用explicit关键字来抑制由构造函数定义的隐式转换Q?/p>
31、动态空间的释放QP119Q?/p> 动态空间的释放使用delete [] pia;Q其中pia为指向动态分配的数组的第一个元素的指针Q。在关键字delete和指针之间的Ҏ(gu)号对是必不可的Q它告诉~译器该指针指向的是自由存储Z的数l,而ƈ非单个对象?/p> 如果遗漏了空Ҏ(gu)号对Q这是一个编译器无法发现的错误,导致程序在q行时出错?/p> 使用std::string后则会自动进行释放,无需deleteQ?/p> 32、c_strq回的数lƈ不保证一定是有效的…?/p> c_strq回的数lƈ不保证一定是有效的,接下来对st1的操作有可能会改变st1的|使刚才返回的数组失效。如E序需要持l访问该数据Q则应该复制c_str函数q回的数l?/p>
33、指向函数的指针 详见?a href="http://www.shnenglu.com/mymsdn/archive/2009/02/01/pointer-to-function.html">指向函数的指针的一点理?/a>?/p>
34、容器初始化 在大多数的程序中Q用默认构造函数能辑ֈ最佌行时性能Qƈ且容器更容易用?/p>
35、容器头文g #include <vector> #include <list> #include <deque> //双端队列“double-ended queue”,发音为“deck?/p>
标准库定义了以上三种序容器cd?/p>
36、容器的容器 必须用空格隔开两个盔R?gt;W号Q以C是两个分开的符P否则Q系l会认ؓ>>是单个符P为右UL作符QƈD~译旉误?/p> 37、P代器范围QP269Q?/p>
C++定义的容器类型中Q只有vector和deque容器提供下面两种重要的运集合:q代器算术运,以及使用除了==?=之外的关pL作符来比较两个P代器Q?=?=q两U关p运适用于所有容器)?/p>
list容器的P代器既不支持术q算Q减法或加法Q,也不支持关系q算Q?lt;=,<,>=,>Q它只提供前|和后置的自增、自减以及相同(不等Q运?/p>
38、容器元素都是副?/p>
在容器中d元素Ӟpȝ是将元素值复制到容器里的。类似地Q用一D元素初始化新容器时Q新容器存放的是原始元素的副本。被复制的原始g新容器中的元素各不相养I此后容器内元素值发生变化时Q被复制的原g会受到媄响,反之亦然?/p>
39、下标操作和.at(n)的区?/p>
vector<string> svec; //empty vector; cout << svec[0]; //run-time error:There are no elements in svec! cout << svec.at(0); //throws out_of_range exception 40、容器的赋|P283Q?/p>
assign操作首先删除容器中所有的元素Q然后将其参数所指定的新元素插入到该容器中。与复制容器元素的构造函CP如果两个容器cd相同Q其元素cd也相同,可以用赋值操作符Q?Q将一个容器赋值给另一个容器。如果在不同Q或相同Q类型的容器内,元素cd不相同但是相互兼容,则其赋D必M用assign函数。例如,可通过assign操作实现vector容器中一Dchar*cd的元素赋lstringcd的list容器?/p>
׃assign操作首先删除容器中原来存储的所有元素,因此Q传递给assign函数的P代器不能指向调用该函数的容器内的元素?/p> 21、vector的动态增长优于预先分配内存?/p> 使用vector的时候最好动态地d元素。它不同于C和Java或其他语a的数据类型,Z辑ֈq箋性,更有效的Ҏ(gu)是先初始化一个空vector对象Q然后再动态添加元素,而不是预先分配内存?/p> 22、vector值初始化 内置->0 有默认构?>调用默认构?/p> 无默认构造,有其他构?>E序员手动提供初始?/p> 无默认构造,也无其他构?>标准库生一个带初值的对象 23、数l下标的cd C++中,数组下标的正类型是size_t而不是intQsize_t是一个与机器相关的unsignedcd?/p> 24、在声明指针的时候,可以用空格将W号*与其后的标识W分隔开来,string *ps与string* ps都是可以的,但后者容易生误解,如: string* ps1,ps2; //ps1是指针,而ps2是一个string对象 也就是说Qh们可能误把string和string*当作两个cdQ或者说string*被当作一U新cd来看待,但这是错?/u>Q?/p> 25、一个有效的指针必然是以下三U状态之一Q?/p> 其中int *pi=0;与int *pi;是不同的。前者是初始化指针指?地址的对象(即ؓNULLQ(pi initialized to address to no objectQ,后者却是未初始化的Qok, but dangerous, pi is uninitializedQ?/p> ~译器可以检出0值的指针Q程序可判断该指针ƈ未指向一个对象,而未初始化的指针的用标准ƈ未定义,对大多数~译器来_如果使用未初始化的指针会指针中存放的不定D为地址Q然后操U该内存地址中存攄位内容,使用未初始化的指针相当于操纵q个不确定的地址中存储的基础数据Q因此对未初始化的指针进行解引用Ӟ通常会导致程序崩溃?/p> 26、void*指针 void*指针只支持几U有限的操作Q?/p> 不允怋用void*指针操纵它所指向的对象?/p> 27、指针和引用的比较(P105Q?/p> 虽然使用引用QreferenceQ和指针都可间接讉K另一个|但它们之间有两个重要区别。第一个区别在于引用L指向某个对象Q定义引用时没有初始化是错误的。第二个重要区别则是赋D为的差异Q给引用赋g改的是该引用所兌的对象的|而ƈ不是使引用与另一个对象关联。引用一l初始化Q就始终指向同一个特定对象(q就是ؓ什么引用必d定义时初始化的原因)?/p> 28、指针与typedefQP112Q?/p> const攑֜cd前和攑֜cd后都可以表示同样的意思: s1和s2均表C常量字W串对象?/p>
但因此就D了下面的句子可能产生误解Q?/p> Ҏ(gu)错把typedef当成文本扩展而生下面的理解Q?/p> 应该从声明的句子看,也就是说只看const pstring cstr;Q在q里pstring是一U指针类型,const修饰的是q个cdQ因此正的理解应该是: 而const pstring cstr;其实可以表示为pstring const cstr;Q这L写法则不Ҏ(gu)产生误解。从叛_左阅ȝ意思就是:cstr是const pstringcdQ即指向string对象的const指针?/p>
29、创建动态数l(注意点见代码注释Q?/p> 但是下面的结果却与概念上的不同: 看来不同的编译器Ҏ(gu)的定义还是有所不同Q注意看*piArray2的|按照说明应该是初始化?Q但q里却仍然表现出?piArray1一L|说明q没有发生初始化?/p>
对于动态分配的数组Q其元素只能初始化ؓ元素cd的默认|而不能像数组变量一P用初始化列表为数l元素提供各不相同的初倹{?/p>
30、const对象的动态数l?/p> 上面的示例的注释来自书中Q但在VC++~译器和G++~译器下却不同,具体表现为: 看来两个~译器对q一问题的看法不太一致?/p> 11、枚?/p> 输出Q?/p> 12、类Q成员变量初始化 定义变量和定义数据成员存在着非常重要的区别:一般不能把cL员的初始化作为其定义的一部分。当定义数据成员Ӟ只能指定该数据成员的名字和类型。类不是在类定义里定义数据成员时初始化数据成员,而是通过成ؓ构造函数的Ҏ(gu)成员函数控制初始化?/p> 13、struct关键?/p>
C++支持另一个关键字structQ它也可以定义类cd。struct关键字是从C语言中承过来的?/p>
如果使用class关键字来定义c,那么定义在第一个访问标号前的Q何成员都隐式指定为privateQ如果用struct关键字,那么q些成员都是publicQ除非有其他Ҏ(gu)的声明,如添加了private才ؓprivateQ否则都是publicQ因此没必要dpublic关键字?/p>
用class和struct关键字定义类的唯一差别在于默认讉KU别Q默认情况下Qstruct的成员ؓpublicQ而class的成员ؓprivate?/p>
14、预~译头文?/p>
一?u>什么是预编译头文g? VC++E序一般包含的头文仉比较复杂Q如果每ơ都逐行分析可能会花很多旉Q所以VC++默认讄是第一ơ编译时分析所有头文gQ生?pch文gQ这个文件很大,但以后每ơ编译时可以节省很多时间。如果删除了q个文gQ下ơ编译时VC++会自动生成它?/p>
二?u>什么时候用预~译? 15 、在头文件中必须L使用完全限定的标准库名字?/p>
因ؓ预处理器会将头文件复制到使用它的M地方Q两U可能,一U是如果在头文g中用usingQ会使相关代码不论是否需要该using都必放|一个usingQ另一U是Q假设有另一个库可能也包含了相应的方法如有方法std::cout以及my::coutQ如果用了usingQ有可能D被引入的E序偏离原本的用意图,或者导致编译错误?/p>
16、字W串字面值和标准库string不是同一U类?/p>
因ؓ历史原因以及Z与C语言兼容Q字W串字面g标准库stringcd不是同一U类型。这一点很Ҏ(gu)引v混ؕQ编E时一定要注意区分字符串字面值和string数据cd的用,q很重要?/p>
17、getline函数输入的时候丢弃末换行W,q将整行q回Q而且不丢弃第一个换行符Q也是即便你一开始就输入了换行符Q它仍然会返回,只不q返回的是一个空字符串而已?/p>
~写E序实现从标准输入每ơ读取一行文本。然后改写程序,每次d一个单? 其中WriteLine函数Q?/p> 18、std::string对象的加?/p>
如果一串字W串和string对象混合相加Q则要求+操作W左x作数必须臛_有一个是stringcd的?/p>
推论Q一串字W串和string对象混合相加Q前两个操作C臛_有一个是string对象?/p> 19、C标准库头文g和C++版本 C++标准库也包括C标准库,命名上则在C标准库的名字前加一个cq省d~.hQ比如C标准库中的ctype.hQ在C++中就有相应的标准库cctypeQ注意没?hQ。C++和C标准库文件的内容是一LQ只是采用了更适合C++的Ş式。而且通常cname头文件中定义的名字都定义在命名空间std内,?h版本的名字却不是q样?/p>
20、关于中文编码的相关问题 我们知道大部分的~译器以及解x案都由外国h发明创造,特别是美国h。因此很多程序默认不支持中文。虽焉着Unicode的普及这部分问题得到了很大的改善Q比如C#可以完地支持中文Q,但是cMC++q样的语aQ仍焉临着中文~码的问题。关于编码,有一值得推荐的文章:地址1Q?a target="_blank" >备用地址Q?a target="_blank" >下蝲后打?/a>QdocxQ?0.7KBQ?a target="_blank" >查找更多 标识W不能包含两个连l的下划U,也不能以下划U开头后面紧跟一个大写字母。有些标识符Q在函数外定义的标识W)不能以下划线开头?/p>
但是在G++~译器和VC~译器下Q二者均可正编译! 2、跨q_~译E序Q?/p>
q里不是要讲解如何跨q_~译E序Q也不是告诉你如何更好地~写通用q_的程序规则,那可能涉及到很多的宏定义以及g相关Ҏ(gu)。这里仅Z用示例代码提供一U精的方式?/p>
用Eclipse+MinGW的方式默认会很精Q所以把它当作一U目标! 用Visual Studio 2008创徏的程序会让你引入预编译头stdafx.hQ这通常发生在用Visual Studio创徏Win32控制台应用程序,q直接点?#8220;完成”后)Q这导致你无法在Eclipse上编写的E序直接q行在Visual Studio上。这时你应该通过修改目属性来获得q种_的方式:Q选择目Q右键属性,选择配置属?>C/C++->预编译头->创徏/使用预编译头Q选择“不用预~译?#8221;->“定”后再ơ编译即可!Q?/p>
3、变量命名习?/p>
4、在C++中,“初始化不是赋?#8221; 初始化指创徏变量q给它赋初始|而赋值则是擦除对象的当前值ƈ用新gѝ?/p>
直接初始化语法更灉|Q效率更高! 对内|类型来_复制初始化和直接初始化几乎没有差别?/p>
对类cd来说Q有些初始化仅能用直接初始化完成。要想理解其中缘由,需要初步了解类是如何控制初始化的?/p>
例如Q?/p>
也可以通过一个计数器和一个字W初始化string对象。这样创建的对象包含重复多次的指定字W,重复ơ数p数器指定Q?/p>
std::string all_nines(10, ‘9’); //all_nines = “9999999999”; 本例中,初始化all_nines的唯一Ҏ(gu)是直接初始化。有多个初始化式时不能用复制初始化。(V注:q里的初始化式即为构造函数的多个重蝲Q这里所谓的“不能使用”应该?#8220;功能有所不及”的意思!Q?/p>
5、变量初始化规则 使用未初始化的变量经常导致错误,而且十分隐蔽。问题出在未初始化的变量事实上都有一个倹{编译器把该变量攑ֈ内存中的某个位置Q而把q个位置的无论哪U位模式都当成是变量初始的状态。当被解释成整型值时QQ何位模式都是合法的值——虽然这个g可能是程序员惌的。因个值合法,所以用它也不可能DE序崩溃。可能的l果是导致程序错误执行和/或错误计?/p>
6、声明和定义 Z能让多个文g讉K相同的变量,C++区分了声明和定义。简单地说就是可以用extern关键字来声明QQ何有分配内存行ؓ的声明都是定义。定义也是声明。声明:标明变量的类型和名字Q定义:为变量分配存储空_q可以ؓ变量指定初始倹{?/p>
举例说明Q?/p>
7、变量的隐藏Q?/p>
提示Q在Visual Studio 2008中用std::string定义一个变量,再通过std::cout其输出Q将会得?#8220;error C2679: 二进?#8220;<<”: 没有扑ֈ接受“std::string”cd的右操作数的q算W?或没有可接受的{?”错误信息Q这时要查头文g中是否包?include <string>。而在Eclipse中则不用如此讄Q具体看~译器版本)。这与标准库实现的具体细节有养I在MSVC中,它在文gProgram Files (x86)\Microsoft Visual Studio 9.0\VC\include\string中被实现Q在GNU中,它在base_string.h中被实现。在使用std::stringӞL包含#include <string>是一个好习惯Q?/p>
8、const对象默认为文件的局部变?/p>
一般声明变量后可以在其它文件中通过extern关键字声明ƈ使用该变量: 但是如果是const则无法访问。可以通过昑ּ指定extern关键字其成为全局可访问对象: 注解Q非const变量默认为extern。要使const变量能够在其他的文g中访问,必须昑ּ地指定它为extern?/p>
9、引?/p>
当引用初始化后,只要该引用存在,׃持绑定到初始化时指向的对象。不可能引用绑定到另一个对象?/p>
也正因ؓ如此Q所以引用比指针的优势就在于Q引用不可以在方法中改Q这使得Ҏ(gu)变量变得安全了?/p>
10、const引用 q里我们要求左侧的类型是一致的Q包括constQ?/p>
非const引用只能l定C该引用同cd的对象?br>const引用则可以绑定到不同但相关的cd的对象或l定到右倹{(具体CZ详见C++Primer v4 P52Q?/p>
例如Q?/p>
~译器会这些代码{换成如以下Ş式的~码Q?/p>
但是如下代码可以执行Q?/p>
输出Qival=1025 refVal=1025// PassArray.cpp : 定义控制台应用程序的入口炏V?
//
#include "stdafx.h"
#include <iostream>
using namespace std;
template <typename T>
void Func1(T, T);
template <typename T>
void Func2(T&, T&);
void Func3(int (&)[10], int (&)[12]);
int _tmain(int argc, _TCHAR* argv[])
{
int a[10], b[12];
Func1(a, b);
Func2(a, b);
Func3(a, b);
return 0;
}
template <typename T>
void Func1(T, T)
{
cout<<"Func1.invoked!"<<endl;
}
template <typename T>
void Func2(T&, T&)
{
cout<<"Func2.invoked!"<<endl;
}
void Func3(int (&m)[10], int (&n)[12])
{
cout<<"Func3.invoked!"<<endl;
}
int large_size = 10000000;
cout_current_time("start init vector!\t");
vector<string> svec1(large_size, "Hello");
vector<string> svec2(large_size, "Hi");
cout_current_time("end init vector!\t");
cout_current_time("start init list!\t");
list<string> slist1(large_size, "Hello");
list<string> slist2(large_size, "Hi");
cout_current_time("end init list!\t");
cout_current_time("start init deque!\t");
deque<string> sdeq1(large_size, "Hello");
deque<string> sdeq2(large_size, "Hi");
cout_current_time("end init deque!\t");
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
#include <time.h>
typedef struct tm * time_type;
time_type get_current_time(void) {
time_t t;
t = time(NULL);
return localtime(&t);
}
#include "stdafx.h"
#include <iostream>
class MyClass
{
public :
typedef int index_t;
index_t twice(index_t in);
};
MyClass::index_t MyClass ::twice(index_t in)
{
return in * 2;
}
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
MyClass obj;
MyClass::index_t x, y;
x = 10;
y = obj.twice(x);
cout<<"x = "<<x<<"; y = "<<y<<";"<<endl;
return 0;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
class MyClass
{
public :
typedef int index_t;
bool same_object(MyClass obj);
public :
MyClass(int default_index = 5)
:default_index(default_index),
m_name("default_name"){}
MyClass::MyClass(std::string name);
public :
int default_index;
std::string m_name;
};
MyClass::MyClass(std::string name)
:default_index(0), m_name(name){}
bool MyClass::same_object(MyClass obj)
{
cout<<"m_name = "<<m_name.c_str()<<endl;
cout<<"obj.m_name = "<<obj.m_name.c_str()<<endl;
return strcmp(obj.m_name.c_str(), m_name.c_str()) == 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
MyClass obj;
cout<<"explicit : "<<obj.same_object(MyClass("default_name"))<<endl;
cout<<"implicit : "<<obj.same_object(string("default_name"))<<endl;
return 0;
}
]]>std::string st1("I am a string object!");
//error C2440: “初始化? 无法从“const char *”{换ؓ“char *?
//char *str = st1.c_str();
const char *cstr = st1.c_str();
std::cout<<cstr<<std::endl;
int m, n;
m = 5;
n = 3;
cout << "Print a line!" << endl;
vector<string> lines(n, " I_am_a_PC_! ");
for (vector<string>::iterator siter = lines.begin(); siter != lines.end(); ++siter) {
cout << *siter;
}
cout << endl;
cout << "Print a paragraph!" << endl;
vector<vector<string> > paragraph(m, lines);
for (vector<vector<string> >::iterator piter = paragraph.begin(); piter
!= paragraph.end(); ++piter) {
for (vector<string>::iterator siter = (*piter).begin(); siter
!= (*piter).end(); ++siter) {
cout << *siter << ends;
}
cout << endl;
}
const string s1;
string const s2;
typedef string *pstring;
const pstring cstr;
const string *cstr; //qƈ非上面例子的正确意思!Q错误)
string *const cstr;
const char *cp1 = "some value";
char *cp2 = "other value";
int *piArray1 = new int[10]; //内置cd没有初始?
int *piArray2 = new int[10](); //内置cd需要加I圆括号Q对数组元素q行初始?
std::string *psArray1 = new std::string[10]; //默认构造函数初始化
std::cout<<"----------"<<std::endl
<<"*cp1\t\t:"<<*cp1<<std::endl
<<"*cp2\t\t:"<<*cp2<<std::endl
<<"*piArray1\t:"<<*piArray1<<std::endl
<<"*piArray2\t:"<<*piArray2<<std::endl
<<"*psArray1\t:"<<*psArray1<<std::endl
<<"----------"<<std::endl;
////Visual Studio & MS VC++
//----------
//*cp1 :s
//*cp2 :o
//*piArray1 :-842150451
//*piArray2 :0
//*psArray1 :
//----------
////Eclipse&G++
//----------
//*cp1 :s
//*cp2 :o
//*piArray1 :4064608
//*piArray2 :4064560
//*psArray1 :
//----------
//P118
//error:uninitialized const array
const int *pciArray1 = new const int[10];
//ok:value-initialized const array
const int *pciArray2 = new const int[10]();
std::cout<<*pciArray1<<std::endl;
std::cout<<*pciArray2<<std::endl;
//enum
enum HttpVerbs { Head, Post, Get, Delete };
HttpVerbs current_verbs = Post;
std::cout<<"Current Verbs = "<<current_verbs<<std::endl;
//error C2440: ?? 无法从“int”{换ؓ“HttpVerbs?/span>
//current_verbs = 3;
current_verbs = (HttpVerbs)2;
std::cout<<"Current Verbs = "<<current_verbs<<std::endl;
HttpVerbs copy_verbs = current_verbs;
std::cout<<"Copy Verbs = "<<copy_verbs<<std::endl;
HttpVerbs future_verbs = (HttpVerbs)((current_verbs + 1)%sizeof(HttpVerbs));
std::cout<<"Future Verbs = "<<future_verbs<<std::endl;
std::cout<<"HttpVerbs Size![by sizeof(HttpVerbs)] = "<<sizeof(HttpVerbs)<<std::endl;Current Verbs = 1
Current Verbs = 2
Copy Verbs = 2
Future Verbs = 3
HttpVerbs Size![by sizeof(HttpVerbs)] = 4
class MyClass1
{
public:
int GetMyValue();
void SetMyValue(int value);
private:
//error C2864: “MyClass1::myValue? 只有静态常量整型数据成员才可以在类中初始化
int myValue = 3; //只需修改为int myValue;卛_
};
预编译头文g物理上与通常的的.obj文g是一LQ但~译入预~译头的.h,.c,.cpp文g在整个编译过E中Q只~译一ơ,如预~译头所涉及的部分不发生改变的话Q在随后的编译过E中此部分不重新q行~译。进而大大提高编译速度Qƈ便于对头文gq行理Q也有助于杜l重复包含问题?/p>
当大?c?cpp文g都需要相同的头文件时?
当某些代码被大量重复使用时?
当导入某些不同库都有实现的函敎ͼq生乱时?/p>
//std::cout<<"getlineQ?lt;<std::endl;
WriteLine("getLine");
WriteLine("P72 ~?/span>);
using std::string;
WriteLine("??NEXT\"q?);
string str;
while(std::getline(std::cin, str))
{
if(str == "NEXT")
break;
std::cout<<str<<std::endl;
}
WriteLine("每输"NEXT\"q?);
while(std::getline(std::cin, str))
{
if(str == "NEXT")
break;
//从第0个开始查扄?/span>
static const std::basic_string<char>::size_type npos = (std::basic_string<char>::size_type)-1;
std::basic_string<char>::size_type firstIndexOfEmpty = str.find_first_of(" ", 0);
if(firstIndexOfEmpty != npos)
std::cout<<str.substr(0, firstIndexOfEmpty)<<std::endl;
else
std::cout<<str<<endl;
}void WriteLine(std::string str)
{
std::cout<<str<<std::endl;
}
std::string str2 = str1 + "this" + " that" + " those";
std::cout << str2 << std::endl;
//error C2110: ?? 不能d两个指针
std::string str3 = "this" + " that" + str1 + " those";
std::cout << str3 << std::endl;
]]>//试变量命名Q?
//error C2632: “int”后面?#8220;double”非法
//int double = 3.14159;
//-------------------------------------------------
char _='a';
std::cout<<_<<std::endl;
//-------------------------------------------------
//warning C4091: “”: 没有声明变量时忽?#8220;bool”的左?
//error C2059: 语法错误: “-”
//bool catch-22;
//-------------------------------------------------
//error C2059: 语法错误: “数字上的错误后缀”
//char 1_or_2 = '1';
//-------------------------------------------------
float Float=3.14f;
std::cout<<Float<<std::endl;
int ival(1024); //直接初始?/span>
int ival = 1024; //复制初始?/span>
//在Eclipse中运行没有出现错误!
//在Visual Studio中运行出现运行时错误Q?/span>
int ival; //没有初始化!
std::cout<<ival<<std::endl;
extern double pi; //声明
double pi; //定义Q声明了pi同时定义了pi
extern double pi = 3.14159; //定义Q因为它为pi分配了初倹{只有当该extern语句
位于函数外部的时候才允许使用初始化式Q否则将D~译错误?/span>std::string s1 = "I am a std::string!";
std::cout<<s1<<std::endl;
for(int s1=3; s1!=0; --s1)
std::cout<<"I am a number(int):"<<s1<<std::endl;
//文g1Q?/span>
int counter;
//文g2Q?/span>
extern int counter;
++counter;
//文g1Q?/span>
extern const int bufSize = getBufSize();
//文g2Q?/span>
extern count int bufSize;
//……使用bufSize
int ival = 1024;
int &refVal = ival;
const int ival = 1024;
const int &refVal = ival;
//错误代码
double dval = 3.14;
const int &ri = dval;
int temp = dval;
const int &ri = temp;
如果ri不是constQ那么可以给ri赋一新倹{这样做不会修改dvalQ而是修改了temp。期望对ri的赋g修改dval的程序员会发现dvalq没有被修改。仅允许const引用l定到需要时用的值完全避免了q个问题Q因为const引用是只ȝ?br> int ival = 1024;
const int &refVal = ival;
++ival;
//++refVal; //error C3892: “refVal” 不能l常量赋?
std::cout<<"ival="<<ival<<"\trefVal="<<refVal<<std::endl;
const double dval = 3.14;
const int &ri = (int)dval;
std::cout<<ri<<std::endl;
输出Q?
]]> Page 30 ( Chapter 2 基本语言) 术cd的存储空间依机器而定?/td>
Page 30 ( Chapter 2 基本语言) 表示整数、字W和布尔值的术cd合称?strong>整Ş(integral type)
字符cd有两U:char和wchar_t。charcd通常是单个机器字?byte)。wchar_tcd用于扩展字符集,比如汉字和日?/td>
Page 31 ( Chapter 2 基本语言) 在位q一U上Q存储器是没有结构和意义的?br>让存储具有结构的最基本Ҏ(gu)是用块(chunkQ处理存储。……虽然确切的大小因机器不同而不同,但是通常?位的块作Z个字节,32位或4个字节作Z个“字QwordQ?/td>
Page 32 ( Chapter 2 基本语言) C++标准q未定义signedcd如何用位来表C,而是由每个编译器自由军_如何表示signedcd。……符号位?Q值就敎ͼW号位ؓ0Q值就?或正数。……有些语a中将负数赋给unsignedcd是非法的Q但在C++中这是合法的?/td>
Page 35 ( Chapter 2 基本语言) Z兼容C语言QC++中所有的字符串字面值都q译器自动在末添加一个空字符?/td>
Page 36 ( Chapter 2 基本语言) 两个盔R的仅q根{制表符或换行符分开的字W串字面|或宽字符串字面|Q可q接成一个新字符串字面倹{?br>//concatenated long string literal
std::cout<<"a multi-line "
"string literal "
"using concatenation "
<<std::endl;
执行q条语句会输出Q?br>a multi-line string literal using concatenation
如果q接字符串字面值和宽字W串字面|会出现什么结果呢Q例如:
//Concatenating plain and wide character strings is undefined
std::cout<<"multi-line" L"literal "<<std::endl;
其结果未定义的(unsignedQ,也就是说Q连接不同类型的行ؓ标准没有定义。这个程序可能会执行Q也可能会崩溃或者生没有用的|而且在不同的~译器下E序的动作可能不同?/td>
Page 36 ( Chapter 2 基本语言) 在一行的末尾加一反斜U符号可此行和下一行当作同一行处理?br>std::cou\
t<<"Hi"<<st\
d::endl;
{h(hun)?br>std::cout<<"Hi"<<std::endl;
注意反斜U符号必L该行的尾字符——不允许其后面有注释或空根{同P后行行首的MI格和制表符都是字符串字面值的一部分。正因如此,长字W串字面值的后行才不会有正常的~进?/td>
Page 39 ( Chapter 2 基本语言) C++是一门静态类型语aQ在~译时会作类型检查?/td>
Page 41 ( Chapter 2 基本语言) 标识W不能包含两个连l的下划U,也不能以下划U开头后面紧跟一个大写字母。有些标识符Q在函数外定义的标识W)不能以下划线开头?/td>
Page 42 ( Chapter 2 基本语言) C++支持两种初始化变量的形式Q复制初始化Qcopy-initializationQ和直接初始化(direct-initializationQ。复制初始化语法用等P=Q,直接初始化则是把初始化式攑֜括号中:
int ival(1024); //direct-initialization
int ival = 1024; //copy-initialization
Page 43 ( Chapter 2 基本语言) 也可以通过一个计数器和一个字W初始化string对象。这样创建的对象包含重复多次的指定字W,重复ơ数p数器指定Q?br>std::string all_nines(10,'9'); //all_nines="9999999999"
本例中,初始化all_nines的唯一Ҏ(gu)是直接初始化。有多个初始化式时不能用复制初始化
Page 44 ( Chapter 2 基本语言) 内置cd变量是否自动初始化取决于变量定义的位|。在函数体外定义的变量都初始化成0Q在函数体里定义的内|类型变量不q行自动初始化?/td>
Page 46 ( Chapter 2 基本语言) extern声明不是定义Q也不分配存储空间?br>…?br>只有当extern声明位于函数外部Ӟ才可以含有初始化式?/td>
Page 50 ( Chapter 2 基本语言) 非const变量默认为externQ要使const变量能够在其他的文g中访问,必须昑ּ地指定它为extern
Page 51 ( Chapter 2 基本语言) 引用只是对象的另一个名?/td>
Page 52 ( Chapter 2 基本语言) const引用可以初始化ؓ不同cd的对象或者初始化为右?br>…?br>非const引用只能l定C该引用同cd的对象?br>const引用则可以绑定到不同但相关的cd的对象或l定到右倹{?/td>
Page 56-57 ( Chapter 2 基本语言) 如果使用class关键字来定义c,那么定义在第一个访问标号前的Q何成员都隐式指定为privateQ如果用struct关键字,那么q些成员都是public。用classq是struct关键字来定义c,仅仅影响默认的初始化讉KU别?br>可以{效地定义Sales_itemcMؓQ?br>struct Sales_item{
//no need for public label, memebers are public by default
//operations on Sales_item objects
private:
std::string isbn;
unsigned units_sold;
double revenues
};
本例的类定义和前面的cd义只有两个区别:q里使用了关键字structQƈ且没有在花括号后使用关键字public。struct的成员都是publicQ除非有其他Ҏ(gu)的声明,所以就没有必要dpublic标号?br>用class和struct关键字定义类的唯一差别在于默认讉KU别Q默认情况下Qstruct的成员ؓpublicQ而class的成员ؓprivate?/td>
Page 59 ( Chapter 2 基本语言) q种行ؓ有一个很重要的含义:当我们在头文件中定义了const变量后,每个包含该头文g的源文g都有了自qconst变量Q其名称和值都一栗?/td>
]]>
记录C++ Primer学习中遇到的需要记忆的东西Q这里仅以我个h为标准进行记录?/p>
[格式]
以下样例代表了本文所描述的所有摘要片D将通过以下模版q行创徏?/p>
Page [PageIndex] ( Chapter [ChapterIndex] [Title of Chapter]) |
[正文] |
[正文]
Page 3 ( Chapter 1 快速入? |
在大多数pȝ中,main函数的返回值是一个状态指C器。返回?往往表示main函数成功执行完毕。Q何其他非零的q回值都有操作系l定义的含义。通常非零q回D明有错误出现。每一U操作系l都有自q方式告诉用户main函数q回什么内宏V?/td> |
Page 3 ( Chapter 1 快速入? |
在书中提到的 用于 80x86 ?Microsoft (R) 32 ?C/C++ 优化~译?14.00.50727.762 ?br>版权所?C) Microsoft Corporation。保留所有权利? cl: 命o?warning D9035 :“GX”选项已否冻Iq将在将来的版本中移?br>cl: 命o?warning D9036 :使用“EHsc”而不使用“GX” |
Page 5 ( Chapter 1 快速入? |
q没有直接定义进行输入或输出QIOQ的M语句Q这U功能是由标准库提供的?/td> |
Page 6 ( Chapter 1 快速入? |
std::cout<<"Enter two number:"<<std::endl; 每个输出操作W实例都接受两个操作敎ͼ左操作数必须是ostream对象Q右操作数是要输出的倹{操作符其x作数写到作ؓ其左操作数的ostream对象?br>Qstd::cin与std::cout相反Q?br>std::cout ?#8592;叻I注意头方向Q?br>std::cin ?#8594;叻I注意头方向Q) …… endl是一个特D之Q称?strong>操纵W?/strong>QmanipulatorQ,它写入输出时Q具有输出换行的效果Qƈh与设备相兌的缓冲区QbufferQ。通过h~冲区,用户可立即看到写入到中的输出?/td> |
Page 16 ( Chapter 1 快速入? |
当我们用istream对象作ؓ条gQ结果是试的状态。如果流是有效的Q也是_如果d下一个输入是可能的)那么试成功。遇到文件结束符Qend-of-fileQ或遇到无效输入Ӟ如读取了一个不是整数的|则istream对象是无效的。处于无效状态的istream对象导致条件失败?br>【本信息针对上文中?br>int sum = 0,value; while(std::cin>>value) //以前很少在while里面使用q样的输?br>…… |
Page 20 ( Chapter 1 快速入? |
Ҏ(gu)作符通过它的左操作数取得有操作数。点操作W仅应用于类cd的对象:左操作数必须是类cd的对象,x作数必须指定该类型的成员? |