1. 每个C++程序必须含有main函数,而且main函数是唯一被操作系统显示调用的函数。 2.std::cout<<"Enter two numbers:"; std::cout<<std::endl; endl是一个特殊值,称为操作符(manipulator),将它写入输出流时,具有输出换行 的效果,并刷新与设备相关联的缓冲区(buffer);忘记刷新输出流可能会造成输出停留在缓冲区中,如果程序崩溃,会导致对程序崩溃位置的错误推断。 3.C++程序中大部分出现的空格符的地方可以用换行符代替。两个例外是:1、字符串字面值中的空格符不能用换行符代替2、空格符不允许出现在预处理指示中 4.定义变量时,应该给变量赋初始值 5.太多的注释混入代码可能会使代码难以理解,通常最好是把一个注释块放在所注释的代码的上方 6.自定义头文件用双引号(“”)把头文件括起来(通常在源文件所在路径),标准库的头文件用<>括起来(在系统路径环境中查找) 7.8位块一个字节,32位块四个字节作为一个字 8.超出取值范围的赋值将会被采取取模操作 9.0开头的字面值整数表示八进制,0x开头的整数表示十六进制 10.定义长整形的时候,应该使用大写字母L,表示扩展精度,避免小写的l与1混淆 123u /*unsigned*/ 123L /*long*/ 11.'a'之前加上L,可以得到wchar_t类型的宽字符字面值 L'a' 12.在一行末尾加'/'可以将此行与下行作同一行处理,但是后面不能加注释或空格 13.命名习惯最重要的是保持一致 14.复制初始化 int ival = 1024; 直接初始化 int ival(1024); //更加灵活且效率更高 初始化不是赋值,赋值是擦除原来的数值 15.计数器初始化string变量 std::string all_nines(10,'9'); 得到的值是9999999999 16.const变量定义后就不能修改,所以必须初始化 17.extern const int bufsize = 1024 对const变量指定extern可以让整个程序中访问const对象 18.引用——对象的另一个名字 int ival = 1024; int &refval = ival; //对引用对象复制必须用与该引用同类型的对象初始化,而且必须在定义引用对象的时候对其初始化赋值 可以读取但不能修改引用的对象 19.枚举类型 enum open_modes {input, output, append = 1 , another}; 第一个枚举成员赋值为0,第二个是1,第三个是1,第四个是2 20.类定义后面要加分号 21.默认情况下struct成员为public,class成员是private 22.预处理可以防止头文件被反复引用 #ifndef SALESITME_H #define SALESITME_H #endif 23.使用命名空间 using std::cin; using std::cout; using std::string; 24.任何储存string的size操作结果的变量必须是string::size_type类型,不要把size的返回值赋值给int变量 for(string::size_type index = 0; index != s.size(); ++index) 25.任何一个大写字母都小于任何一个小写字母 26.对字符串进行混合连接操作时,+操作符的作用操作数必须至少有一个是string类型的 错误的连接: string s1 = "hello" + ", "; string s2 = "hello" + "11" +s1; 27.C标准库的文件命名name.h形式在C++中为cname.h 28.C++程序员优先选用!=而不是<来编写循环判断条件 29.vector可以使用下标操作,但是下标必须是已经初始化的元素才 错误的尝试使用下标对vector进行添加操作方法: vector<int> ivec; for (vector<int>::size_type ix = 0; ix != 10; ++ix) ivec[ix] = ix; //错误,ivec没有元素初始化 vector的添加元素 for (vector<int>::size_type ix = 0; ix != 10; ++ix) ivec.push_back(ix); 30.所有的标准库容器都定义了相应的迭代器类型,只有少数容器支持下标操作 vector<int>::iterator iter; 31.每种容器定义都定义了一对命名为begin和end的函数 32.迭代器使用示例: for (vector<int>::iterator iter = iver.begin();iter != ivec.end(); ++iter) //end操作返回的迭代器不指向vector中任何实际元素 *iter = 0; //解引用操作符*,访问迭代器指向的元素 33.声明一个const迭代器的时候,必须初始化迭代器 34.二进制位集处理标准库bitset,在定义bitset时要明确bitset含有多少位 bitset<32> bitvec; 长度值必须是整型值常量或者是已用常量值初始化的整形的const对象 35.用string对象初始化bitset对象时,string对象直接表示为位模式。从string对象读入位集的顺序是从右到左 string strval("1100"); bitset<32> bitvec4(strval); bitvec4位模式中第2和第3的位置为1,第0和第1位置为0。 string 和 bitset对象之间是反向转化的 36.数组一经创建,就不允许添加新的元素。指针则可以像迭代器一样用于遍历和检查数组中的元素 37.C++应尽量使用vector和迭代器类型,而避免使用低级的数组和指针 38.非const变量和要到运行阶段才能知道其值的const变量都不能用于定义数组的维数 const unsigned sz = get_size(); 39.char ca[] = {'C','+','+','/0'}; 使用一组数组字面值初始化字符数组时,要注意添加结束字符串的空字符 const char ca[6] = "Daniel"; //错误,应该7个字符元素,一个用于存放空字符null 40.vector使用vector::size_type作为下标的类型,而数组下标类型是size_t 41.指针的两种定义方法 string *p; string* p; 42.string* p1, p2; //只有p1是指针,p2是string对象 43.void*指针可以保存任何类型对象的地址 44.在表达式中使用数组名时,该名字会自动转换为指向数组第一个元素的指针 45.C++强制要求指向const对象的指针也必须具有const特性 const double *cptr ; 46.使用标准库函数strncat和strncpy比strcat和strcpy函数更安全 47.在复制和串联字符串时,要注意算上结束符null 48.标准库函数strlen返回的是字符串的长度,并不包括字符串结束符,在获得字符串长度上必须加1以便知动态分配时预留结束符的存储空间 49.在要求C风格字符串的地方不可直接使用标准库string类型对象 char *str = st2.c_str(); 50.一元操作符的优先级最高 51.string s("Expressions in C++ are composed..."); string :: iterator it = s.begin(); while(it != s.end() && !isspace(*it)){ *it = toupper(*it); ++it; } 52.if(i<j<k) 该条件将k和0或者1比较 53.位操作符最好使用unsigned整型操作数 54.移位操作的右操作数必须是正数而且必须严格小于左操作数位数的值 55.位异或,两个位之间不同,则为1,相同为0 56.移位操作符比关系操作符、赋值操作符、条件操作符高 cout<<(10<42); 57.只有在必要的时候才使用后置操作符 58.点操作符,用于获取类类型对象的成员 item1.same_isbn(item2); 59.sizeof操作符返回值类型为size_t 60.double向int转换自动按截尾形式进行 61.while(cin >> s) 这里隐式使用了IO标准库定义的类型转换 62.强制将dval类型转换成int类型 ival *= static_cast<int>(dval); 63.空语句常见于循环条件判断阶段就能完成全部循环工作的情况 使用是最好加上注释,以便使任何读这段代码的人都知道该语句是有意省略的 64.在while或者if条件后面额外添加分号,往往会彻底改变程序员的意图 65.block(块)标识了一个作用域 66.if和else匹配时,可以使用花括号指定匹配 67.switch语句中两个case具有相同的数值,会导致编译错误 68.for语句的init-statement中可以定义多个对象,但只能出现一个语句,而且必须具有相同的类型 69.break只能出现在swich语句中 70.string inbuf; while (cin >> inbuf && !inbuf.empty()) { if (inbuf[0] != '_') continue; }//只有下划线开头的单词才做处理 71.使用NDEBUG预处理变量实现有条件调试代码 int main() { #ifndef NDEBUG ceer << "starting main" << endl; #endif } NDEBUG定义了,自动跳过 72.if (word.size() < threshold) cerr << "Error" << _ _FILE_ _ //文件名 <<" :line" << _ _LINE_ _ << endl //当前行号 << " compiled on " << _ _DATE_ _ //文件被编译的日期 << " at " << _ _ TIME _ _ << endl; //文件被编译的时间 73.void fcn(const int i) {} void fcn(int i) {} 发生错误,在C语言中,具有const形参或非const形参的函数并无区别 74.将实参定义为引用类型 void swap (int &v1, int &v2) { int tmp = v2; v2 = v1; v1 = tmp; } 参数值在函数内产生的修改可以被传到函数外 75.非const引用形参只能与完全同类型的非const对象关联 76.应该将不需要修改的引用形参定义为const引用 .编译器检查数组形参关联的实参时,只会检查实参是不是指针、指针类型和数组类型是否匹配,不会检查数组长度 77.f( int &arr[10]) f( int (&arr)[10]) &arr两边的括号是必须的,因为下表操作符具有更高的优先级 78.多维数组编译时编译器忽略第一维的长度 79.确保函数的操作不超过数组实参的边界的方法: 1:数组本身放置一个标记来检测数组的结束。C语言 2:传递指向数组第一个和最后一个元素的下一个位置的指针。 3:将第二个形参定义为数组的大小 80.只允许主函数main没有返回值就结束 81.在含有return语句的循环后没有提供return语句是很危险的 82.千万不要返回局部对象的引用 函数执行完毕是,将释放分配给局部对象的存储空间,此时对局部对象的引用将会指向不确定内存 83.一个函数只能定义一次,但可以声明多次 84.主函数不能调用自身 85.如果提供了实参,将覆盖默认的实参值 sring scr(string::size_type height = 24, string::size_type width = 80, char background = ' '); string screen; screen = scr();//默认实参 24 80 ' ' screen = scr(66);//60 默认实参 80 ' ' screen = scr(66,256);//66 256 默认实参 ' ' screen = scr(66,256,'#');//66 256 '#' 尽量使最少使用默认实参的形参排在最前,最可能使用默认实参的形参排最后 86.形参也是自动对象,只有在函数被调用的时候才会存在的对象是自动对象 87.static对象一旦被创建,在程序结束前都不会被撤销 88.使用内联函数 inline const string shorterString(const string &s1, const string &s2) { retuen s1.size() < s2.size() ? s1 : s2; } cout << shorterString( s1,s2) << endl; 相当于 cout << (s1.size() < s2.size() ? s1 : s2) << endl; 89.内联函数应该在头文件中定义,不同于其他函数 90.构造函数 与类同名,而且没有返回类型 在创建类类型对象时使用的初始化式 91.在类定义外面定义的成员函数必须指明它们是类的成员 92.函数不能仅仅基于返回类型来实现重载 93.C++中的引用变量、默认实参和函数重载 引用变量讲得通俗一点就是变量的别名。int a=2;int &b=a; 默认实参是指当函数调用中省略了实参时自动使用的一个值。 94.排列形参时,把最少使用默认实参的形参放在最前,最可能使用默认实参的形参排在最后 95.默认实参只能指定一次 96.使用重载对程序未必是件好事 97.函数的声明要放在头文件中 98.含有多个形参的重载确定,程序选择匹配最佳的函数 99.仅仅当形参是引用或指针时,形参是否为const才有影响 100.不能仅仅基于指针是否为const来实现函数的重载 f(int *) f(int *const);//错误 101.指向函数的指针 bool *bf(const string &,const string &); 102.使用typedef简化函数指针的定义 typedef bool (*comFcn)(const string &,const string &); bool lengthCompare(const string &,const string &); comFcn pf1 = 0; comFcn pf2 = lengthCompare; 只能使用同类型的函数或函数指针或0值常量表达式进行初始化或赋值 103.函数的形参指向函数指针的两种编写方式 void useBigger(const string &,const string &,bool (const string &,const string &)); void useBigger(const string &,const string &,bool (*)(const string &,const string &)); 104.IO类型的头文件中定义:iostream定义读写控制窗口的类型 fstream定义读写已命名文件的类型 sstream定义储存在内存中的string对象 105.对stream类型添加国际字符支持者原类型前加c wchar_t,wifstram,wofstream,wfstream 对应的标准输入对象wcin,标准输出wcout,标准错误wcerr 106.标准库类型(IO,ofstream,instream)不允许做复制或赋值操作 只有支持复制的元素类型才能储存在vector或者其他容器类型中,所有流对象不能存储在vector或其他容器中 返回值也不能为流类型 107.检测是否可用的最简单方法就是检查其是否为真值 If(cin) While(cin>>word) 108.IO的条件状态bad,fail,eof,good操作提示 109.流状态的查询和控制 int ival; While(cin>>ival,!cin.eof())//直到读到文件结束符为止,注意这里while有两个参数 { If(cin.bad())//检查流是否已经被破坏 Throw.runtime_error("IO stream corrupted!"); If(cin.fail())//如果输入无效,输出警告并且清除failbit状态 { Cerr<<"bad data,try again"; Cin.clear(istream::failbit); Continue; } } 110.多种状态管理 Is.setstate(ifstream::badbit | ifstream::failbit); 111.输出缓冲区的刷新的方法 Cout<<"hi!"<<flush;//刷新流,但不在输出中添加任何字符 Cout<<"hi!"<<ends;//在缓冲区中插入字符null然后刷新 Cout<<"hi!"<<endl;//输出一个换行符并刷新缓冲区 112.Unitbuf操作符刷新所有输出,在每次执行完写操作后都刷新流 Cout<<unitbuf<<"first"<<"second"<<nounitbuf; 相当于 cout<<"first"<<flush<<"second"<<flush; 113.如果仅仅因为缓冲区没有刷新,很容易浪费很多时间进行调试,所以要经常使用endl而非'/n' 114.使用c_str成员获取C风格字符串,调用open或使用文件名作为初始化式时,需要传递的实参为C风格字符串,比较好的方法是把文件名读入string对象 Ifstream input; Vector<string>::const_iterator it = files.begin(); While(it != file.end()) Input.open(it->c_str())//打开文件,注意这里要打开为string对象,用c_str()成员 { If(!input) Break; While(input >> s) Process(s); Input.close(); Input.clear(); ++it; } 115.重新捆绑文件时,必须先关闭现在的文件 Ifstream infile("in");//打开文件名为in的文件读取 Infile.close();//必须先关闭后再读取第二个文件 Infile.open("next");//打开文件名为next的文件读取 116.如果需要重用文件流读写多个文件,需要在读另一个文件前调用clear清除该流的状态 117.顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定 118.顺序容器类型:vector (支持快速随机访问)list(支持快速插入删除) deque(双端队列) 顺序容器适配器 stack(后进先出) queue(先进先出) priority_queue(有优先级管理的队列) 119.使用顺序容器需要使用的头文件 #include <vector> #include <list> #include <queue> 120.容器的声明方法 容器类型加容器中元素类型 vector<string> svec; List<int> ilist; 121.将一个容器复制给另一个容器时,类型必须匹配,容器类型和元素类型都必须相同 但使用迭代器的时候,不要求容器类型相同,元素类型也可以不相同,只要他们相互兼容 122.初始化指定数目的元素 Const list<int>::size_type list_size = 64; List<string> slist(list_size,"eh?");//list容器中初始化为64个"eh?"的字符串 接受容器大小做形参的构造函数只适用于顺序容器 123.容器元素类型的约束:1必须支持赋值运(引用不支持一般意义上的赋值运算) 2元素类型的对象必须支持复制 (IO库类型不支持赋值或复制运算) 124.外加的数据类型需要提供大小并提供单个初始化式的构造函数,假设Foo类型没有构造函数,但提供了一个int类型形参的构造函数 Vector<Foo> empty;//声明成功,不指定容器大小和容器内元素 Vector<Foo> bad(10);//没有构造函数不能仅指定容器大小进行声明 Vector<Foo> ok(10,1);//由于有int形参的构造函数,所以声明成功 125.必须用空格隔开相邻的>符号,否则会被系统认为是>>操作符 Vector<vector<string> > lines; Vector<vector<string>> lines;//错误 系统认为是位操作符 126.只有vector 和 deque容器提供迭代器算术运算和用== 和!=以外的关系操作符比较容器 关系操作符仅仅适合vector和deque容器这两种容器都支持元素位置的随机访问,因此可以有效实现算术和关系运算 Vector<int>::iterator iter = vec.begin() + vec.size()/2;//取中值 127.begin()返回迭代器的第一个元素,End()迭代器指向的是最后一个元素的下一个位置 元素表示范围为[first,last) 128.first和last不相等的时候 迭代器范围内至少有一个元素,相等时,迭代器为空 rbegin()返回一个逆序迭代器,指向最后一个元素,rend()返回一个逆序迭代器,指向第一个元素前面的位置 129.所有容器都支持c.push_back(t)操作,在容器尾部插入一个元素,c.push_front(t)只适用于list和deque容器,在前段添加元素,c.insert(p,t)适用于p前插入值为t的新元素,c.insert(p,t)在p指向的元素前插入值为t的新元素,c.insert(p,n,t)在p指向的元素前插入n个值为t的元素,p指向的元素钱插入迭代器b和e标记的范围内的元素 130.使用一段新元素初始化容器时,新容器存放的是原始元素的副本 131.不要存储end操作返回的迭代器,添加或删除deque或vector容器内的元素都会导致存储的迭代器失效 132.容器的比较,如果两个容器都不是对方的子列,比较的结果取决于所比较的第一个不相等的元素 133.C++语言只允许两个容器做元素类型定义的关系运算 134.容器大小操作c.size()返回容器内元素个数,c.max_size()返回容器容量,c.empty()判断容器是否为空,c.resize(n)增加容器n个大小 135,c.front()和c.back()返回第一个和最后一个成员,c[n]/c.at[n]返回下标为n的元素应用 136.必须先检测迭代器是否为空,再进行操作 137.c.erase(p)删除迭代器p指向的元素,c.erase(b,e)删除迭代器b和e说标记范围内的所有元素c.clear()清除所有容器元素(或者将begin和end迭代器传递给erase函数),c.pop_back()删除最后一个元素,c.pop_front()删除c 的第一个元素,这两个返回值都是void 138.顺序容器的赋值操作 c1 = c2 删除c1中所有元素,把c2赋值给c1。c1.swap(c2)交换c1 c2,c.assign(b,e)重置c中的元素替换成b和e标记范围内的元素,b和e标记的必须不是c(可以用assign赋值不相同但兼容的元素给c),c,assign(n,t)把c重置为n个值为t的元素 139.vector内的元素是顺序存储的,便于随机访问 140.c.capacity()显示c中剩余的存储空间,c.size()显示c中当前拥有的元素个数 141.选择容器的法则(1)如果要求随机访问,选择vector或者deque (2)必须在容器中间插入或者删除元素,选择lis (3)程序在容器首部或者尾部插入或删除元素,应该采用deque容器 (4)可以根据情况先使用list容器,再复制进vector以实现随机访问 142.使用迭代器而不是下标操作容器,可以防止未定义的操作 143.string类型可以视为字符容器,但是不支持以栈的方式操作,front、back、pop_back 144.substr操作,在指定string对象中检索需要的子串 s2 = s1.substr(6,5);//检索需要的子串,从第六个字符开始的5个字符,s2.substr(6)检索从第六个字符开始到最后字符的所有子串 145.string::size_type pos = name.find("Anna"),在name中查找Anna子串的位置,使用string::size_type储存find的返回值 146.关联容器通过键存储和读取元素,map类似字典,一一对应,multimap 147.pair类型 在utility头文件定义 pair<string,string> anon; pair <string ,int> word_count("Jack",18); 148.pair成员first second pair.first 149.make_pair函数,由传递它的两个实参产生一个新的pair对象 next_auth = make_pair(first ,last); 150.map对象 在map头文件中定义,理解为关联数组,通过键作为下标获取值,但是是与键相关联的,使用时必须指明键和值的类型 151.键类型唯一的要求就是必须支持<操作符,所用的比较函数必须在键类型上定义为严格弱排序 152.使用下标访问一个不存在的元素将导致map容器中添加一个新元素,它的键为下标值 153.map下标操作符返回的类型与对map迭代器进行解引用获得的类型不相同,迭代器返回value_type类型的值(const key_type和mapped_type类型成员的pair对象),下标操作符返回mapped_type类型的值 154.map容器插入单个元素的insert版本,迭代器必须指向键-值pair类型的元素,map容器接受单个值的insert版本返回类型 155.m.insert(e)如果e不在m中,则插入,如果在m中,则m保持不变,不做任何操作,返回一个pair类型对象,<指向e.first的map迭代器,一个表示是否插入成功的bool类型的对象> 156.m.count(k)返回m中k的出现次数 m.find(k)如果m容器中存在按k索引的元素,则返回指向该元素的迭代器 157.防止在map中查找元素找不到后插入元素值,先用count查找一下容器中的数量 if(word_count.count("foobar")) occurs = word_count["foobar"]; 158.使用迭代器遍历map容器时,迭代器元素按键的升序排列 159.map容器erase操作返回void,顺序容器erase操作返回迭代器,指向被删除元素后面的元素 160.set容器只是单纯键的集合(key_type),没有关联值,set键也只能唯一,且 不能修改,只想知道键是否存在时,使用set容器,必须使用set头文件 161.map和set容器中仅会有不同元素出现 162.set容器count返回值只会是1或0 163.multimap和multiset允许一个键多个定义但是不支持下标运算 164.关联容器map和set都是按顺序存储,multimap和multiset一个键对应的多个实例是相邻存放 165.泛型算法,提供一组不依赖特定容器类型的功能函数 头文件<algorithm> 166.每个泛型算法都独立于单独容器,但是算法不直接添加或删除元素 167.所有迭代器都支持自增操作符 168.accumulate算法 int sum = accumulate(vec.begin(),evc.end(),42);//累加输入范围内的说有值 string sun = accumulate(v.begin(),v.end(),string(""));//把string类型的vector容器中的元素连接起来 169.find_first_of有两对迭代器参数,在第一段范围内查找与第二段范围中任意元素匹配的元素,指向第一个匹配的元素,如果找不到匹配元素,返回第一个范围的end迭代器 list<string>::iterator it = roster1.begin(); it = find_first_end ( it , roster1.end() , roster2.begin() ,roster2.end())) != roster1.end(); roster1和roster2类型不必精确匹配,roster1可以是list,roster2可以是vector,只要两个元素可以使用操作符比较就行 170.必须保证算法所写的序列至少足以存储要写入的元素,写入到输入序列的算法本质上是安全的-只会写入与制定输入范围数量相同的元素 171.copy算法 从输入范围中读取元素,然后复制给目标ivec vector<int> ivec; copy(ilst.begin(),ilst.end(),back_inserter(ivec)); 172.unique算法,删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器,实际上没有删除,只是把无重复的元素复制到了序列的前端,覆盖相邻的重复元素 173.标准库所定义的迭代器不依赖与特定的容器。所有的容器都定义了自己的reverse_iterator类型,由rbegin和rend成员函数返回,在头文件iterator中定义 174.在vector或者其它没有push_front运算的容器上使用front_inserter将会产生错误 175.在指定位置插入的迭代器inserter,两个实参(所关联的容器和指示起始插入位置的迭代器) 176.inserter函数总是在它的迭代器实参所标明的位置前面插入新元素,和使用front_inserter函数的插入不同,一旦inserter插入一个新元素后,插入位置就不是容器的首元素了,如果使用front_inserter元素将以相反的次序出现在目标对象中 177.流迭代器:istream_iterator读取输入流,ostream_iterator写输出流,流迭代器只定义了最基本的迭代器操作,istream提供比较两个迭代器是否相等,但是ostream不提供比较运算 178.ostream_iterator<T> in(strm,delim);创建T类型对象的迭代器写入到strm输出流,以delim作为分隔符 179.自增的效果是使迭代器在流中移动到下一个值 180.ostream_iterator<string> out_iter(cout,"/n"); istream_iterator<string> in_iter(cin),eof; while (in_iter != eof) *out_iter++ = *in_iter++; 这个程序不断读cin,并把每个读入的值写入到cout不同行中 181.对于反向迭代器,++运算将会访问前一个元素,而--运算将会访问下一个元素,反向迭代器如rbegin和rend成员分别指向容器尾元素和首元素前一位置 182.使用普通的迭代器对反向迭代器进行初始化或者赋值时,所得到的迭代器并不是指向原迭代器所指向的元素 183.泛型算法要求制定范围内的两个迭代器必须是相同的类型,如find_first_of(it,roster1.end(),roster2.begin(),roster2.end());中如果it是const_iterator对象而roster2是interator对象则将导致无法编译 184.迭代器的一般操作(不同类型的迭代器对操作的支持不同): 1.比较操作 == 或 != 2.前置和后置的++自增操作 3.解引用操作* 4.箭头操作符-> (*).member 5.关系操作符 < <= > >= 6.下标操作符iter[n],相当于*(iter + n) 185.由于关联容器map和set的键是const对象,所以关联容器不能使用任何写序列元素的算法,可以把关联容器视为支持自减运算的输入迭代器,而不是完整的双向迭代器 186.list容器上的迭代器是双向的,不是随机访问类型,所以不支持随机访问 187.list容器有一些特有的算法,可以优先使用而不是使用泛型算法 188.在public上定义的成员可以被所有使用该类的代码访问,在private上定义的成员可以被其他类成员访问,所有成员必须在类内部声明 189.构造函数给每个数据成员设置适当的初始值Sales_item(): units_sold(0), revenue(0.0) {},但是不能指定返回类型,可以对构造函数进行重载,在定义新对象是,可以通过传递不同的参数来确定使用哪个构造函数 成员名和带括号的初始值组成,跟在构造函数的形参表后,以冒号开头 190.成员函数的定义可以在类外进行,但是声明必须在类内声明,在类内部定义的函数默认为inline,在类外部声明的函数要指明它是在类的作用域中,Sales_itme::avg_price,表示在Sales_items类中avg_price函数定义 191.被封装的元素隐藏了它们的实现细节,大多数类类型隐藏了实现该类型的成员 192.struct默认是public,class默认是private 193.数据抽象和封装的优点:避免用户对类内部成员的误用,代码需要修改时可以在类内部修改,不需要修改用户代码 194.类发生改变时,使用该类的代码必须重新编译 195.使用类型别名简化类 typedef std::string::size_type index; 196.通常不在类定义体内定义inline成员函数,通常是放在有类定义的头文件中 197.类的前向声明-声明一个类而不定义他,一般用于编写相互依赖的类 198.类的数据成员可以是指向自身类型的指针或引用 199.class(struct) Sales_item item1; 声明一个类 200.类的定义要以分号结束,因为在类的定义后可以接对象定义列表(这是不提倡的) class Sales_item {}; class Sales_item {} accum,trands; 201.成员函数具有一个附加的隐含形参(this),就是指向该类对象的一个指针,当要把一个对象作为整体引用而不是引用对象的一个成员时,必须要使用this指针 202. class Screen{ public: Screen& move(index r, index c); Screen& set(char); Screen& set(index,index,char); }; Screen& Screen::set(char c) { contents[cursor] = c; return *this; } 该函数返回自身类类型的对象的引用,每个函数都返回调用自己的对象,通过对this指针的解引用来访问this指向的对象,this指针相当于返回函数的使用者 myScreen.move(4,0).set('#').set(4,4,'#'); .move(4.0)返回一个myScreen,被set('#'),调用,set('#')同时也返回一个myScreen 203.const成员函数只能返回*this作为一个const引用,非const成员不能调用,解决方法是,定义一个基于const的重载,当要返回const对象时就调用对应的const函数,非const对象时调用非const函数 204.声明一个const成员函数 void Screen::display(std::ostream& os) const {}; 205.在const成员函数中,如果希望中间的数据可以修改,可以讲成员声明为mutable 206.作用域操作符来访问类的定义成员,Screen::index出现在类的定义体之外的成员定义必须指明成员出现在哪个类中 207.显式的指定成员名或者显式使用this指针可以防止同名实参被形参屏蔽 208.函数的初始化发生在计算阶段前,在开始执行构造函数的函数体前,要完成初始化,所以初始化const成员的唯一机会就是在构造函数初始化列表中 209.必须对任何const或者引用类型成员以及没有默认构造函数的类类型的任何成员使用初始化式 210.按照与成员声明一致的次序编写构造函数的初始化列表,最好使用构造函数的形参进行初始化,否则如果一个成员基于其他成员初始化,可能会造成错误 class X{ int j; int i; public: X(int val): i(val),j(i){} }; 211.只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数,如果仅定义了一个带参数的构造函数,那么每次定义时都要带参数 212.类成员的显示初始化必须根据数据成员的声明次序来使用初始化式,显示初始化的缺点是要求所有成员都是public类型,所以推荐使用构造函数 213.友元就是类可以指定函数或类让这个类可以有访问自己非公有成员的权限,用关键字friend声明,友元出现在类定义的内部 class Screen { friend class Window_Manege; } Window_Manege& Window_Manege::relocate(Screen::index r,Screen::index c,Screen& s) { s.height += r; s.weight += c; return *this; } 如果不声明friend友元,那么将会不允许使用形参s的height和weight成员 214.也可以声明其它类的成员函数为友元 215.必须先定义要使用友元的对象的函数或者类,然后才能对其声明友元