| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3201 人关注过本帖, 6 人收藏
标题:C++学习笔记,已结束
取消只看楼主 加入收藏
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
结帖率:100%
收藏(6)
 问题点数:0 回复次数:17 
C++学习笔记,已结束
篇首:
    再过一个月大二就结束了,上的大专,所以就要被赶出去找工作。感到很迷茫,也很恐慌。在这两年里,图书馆里的书乱七八糟什么都看过,犯了贪多的毛病。想学习下Windows编程,但是很反感GDI那些东西;看完PHP,又不喜欢网页的表格、排版等,到头来什么也不会做。一个多月前,看到一个愿意培养新人的公司,希望在暑假前自学完C++,前去求职学习。
    刚才看了些牛人的博客,心里也很郁闷。感觉学习的进度为什么这么慢。心里告诉自己不要急躁。但,唉。从小到大,都不敢跟别人一样,在做事之前,都拍着胸脯打保证说没问题,趁着心里面的复杂感受,赶紧壮着胆注册了帐号,希望借本帖的小地方督促自己学习,怕自己半途而废,也免得我光看一遍,没有怎么实际练习过。

    本人状况:非计算机专业  熟悉C  能看懂点汇编  没有学习过数据结构  基本算法也都不知道
    使用教材:C++ Primer 中文版(第4版)

    更新安排:23号晚上开始跟帖更新,以后每日晚上更新,由于目前已经看到 顺序容器 9.3.7  所以在近两天,如果我们不补课的话,尽快把前面补上。(只剩一个月,有好多实验和实训,还要结课,所以有点忙)

    如果此贴违反相关规定,请版主在删帖之余,麻烦发个说明给我。谢谢。

[ 本帖最后由 naruto01 于 2011-7-3 17:34 编辑 ]
搜索更多相关主题的帖子: 找工作 Windows 博客 图书馆 网页 
2011-05-23 01:18
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
谢谢楼上两位的支持。我也知道坚持很不容易,所以才这样做。因为比较要面子,希望可以成为坚持下来的动力吧
昨天访问不了 现在补上昨天的笔记

程序代码:
2011.5.23
第一章    快速入门
    这一章让我见识了下C++程序是什么样子的,以及了解了一点非常重要的概念:类。大概看下,明白个大意就行了。
    在整个学习过程中,我比较注重对正确做法的理解或选择相对省事的做法,可能会省略掉一些关于错误行为的分析和解释。
    值得注意的有:
        1.C++中,每个表达式都产生一个结果。   输出操作(std::cout <<)返回值是输出流本身,输入流同样。
        2.命名空间(namespace)的概念。    在初级学习中,一般加上using namespace std;即可。
        3.从开始学习,就应该养成遵循规范的良好习惯。    比如#include <iostream>与C语言中的区别。
        4.在适当位置声明变量,更有助于规范程序思路。    比如for(int i = 1; i <= 10; ++i);

    就以最基本的一个C++程序来结束这一章的学习吧。
        //这是我的第一个C++程序
        //code by naruto01
        #include <iostream>
        int main()
        {
            for(int i = 1; i <= 10; ++i)
                if((i % 2) != 0)
                    std::cout << "Hello,World!" << std::endl;
            return 0;
        }
        
第二章    变量和基本类型
    本章介绍了C++变量和基本类型的相关内容,比较重要的有const限定符、引用、typedef以及类类型。
    2.1基本内置类型中,值得注意的是C++中把负值赋给unsigned对象是合法的,结果是该负数对2^n(n是该类型的存储位数)求模后的值。
    2.2字面值常量,有宽字符概念,即在字面值前面加L。 宽字符是一个字符用两个字节来存放。
    2.3变量
        注意“左值”和“右值”的概念。
            左值(lvalue)可以出现在赋值语句的左边或右边。
            右值(rvalue)只能在右边。
        C++中的标识符区分大小写。
        保持一致的命名习惯。
        在变量定义时指定了初始值,称为初始化。 要注意对未初始化的变量使用可能引起运行问题,所以最安全和容易的做法是对每个内置类型变量进行初始化。
        类通过构造函数进行初始化。
        变量名的作用域 http://learn.对作用域的解释很好理解
        引用使用&进行定义,并且必须初始化,不能定义引用的引用。
        typedef的使用目的:
            为了隐藏特定类型的实现,强调目的
            简化
            允许一种类型用于多个目的
        类在定义后面需要添加分号(;)。
            类中的操作和数据称为类的成员。
            访问标号这里介绍了有public、private。
            struct和class的唯一差别在于,class在没有访问标号时,任何成员都是private;struct则为public。    
        预处理时避免多重包含的技巧:
            #ifndef MY_MARK
            #define MY_MARK
            #endif
            
    一小段程序
        //myclass.h
        #ifndef MY_MARK
        #define MY_MARK
        #endif
        
        class my_class {
            public:
                std::string  str;
        };
        
        //主程序
        //code by naruto01
        #include <iostream>
        #include "myclass.h"

        typedef class my_class my_defed;

        int main()
        {
            my_defed test;
            std::string &ref = test.str;
            std::cin >> test.str;
            std::cout << "本体:" << test.str << std::endl;
            std::cout << "引用: " << ref << std::endl;
            return 0;
        }


[ 本帖最后由 naruto01 于 2011-5-24 19:56 编辑 ]
2011-05-24 19:07
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
程序代码:
2011.5.24
第三章    标准库类型
    在头文件中,必须总是使用完全限定的标准库名字。
    string类型的输入操作符需要注意有两点:
        1.读取并忽略开头所有的空白字符。
        2.读取字符直至再次遇到空白字符终止。    
    使用getline读取整行文本,和上述特点配合,可以有效分解句子中的单词。例子将在IO操作看到。
    string对象size()操作返回的是string::size_type类型。    这表示应使用相关库类型的配套类型,它们的使用与机器无关,并可以减少错误发生。
    在3.2.3的6中,有一例子string s5 = s1 + ", " + "world";     s1 + ", "    返回string对象,然后再与"world"进行连接。也体现了第一章的描述:C++中,每个表达式都产生一个结果。
    string对象字符处理的相关函数定义在cctype头文件中。    cname表示这个头文件源自C标准库。
    
    vector是同一种类型的对象的集合。使用应包含#include <vector>。
    vector是一个类模版,而vector<int>则是数据类型。
    vector是可以动态增长的。    简直太爽了,C写程序时一直愁数组大小不能更改,如果想动起来,就得自己进行内存管理,很麻烦,难怪vector应用很普遍。
    C++程序员习惯优先选用!=进行循环判断条件。
    
    迭代器是一种检查容器内元素并遍历元素的数据类型。    可以想象成一种智能、自适应的特殊指针,这样对于迭代器的操作,对于熟悉C的人来说,更快理解。
    每种容器通过begin和end函数返回迭代器。其中begin指向第一个元素,而end返回的是“容器末端元素的下一个”。
    任何改变vector长度的操作都会使已存在的迭代器失效。    在使用迭代器的时候,要特别注意当前使用迭代器是否仍然有效,这是很容易被忽视导致的错误。
    
    bitset类型使直接操作若干位提供了方便。
    size_t类型定义在cstddef中,是一个与机器相关的unsigned类型,大小足以保证存储内存中对象的大小。    在一些程序的源代码中经常看到这个类型,后面数组的下标也应使用size_t。
    
    //code by naruto01
    #include <iostream>
    #include <string>
    #include <cctype>
    #include <vector>

    //这里啰嗦一次,以后using namespace std; 
    using std::cin;
    using std::cout;
    using std::endl;
    using std::string;
    using std::vector;

    int main()
    {
        string s;
        if(s.empty())
            cin >> s;
        s += " naruto01";
        cout << s << endl;
        //s转换成大写形式
        for(string::size_type ix = 0; ix != s.size(); ++ix)
            s[ix] = toupper(s[ix]);
        cout << s << endl;
    
        vector<int> ivec(12, 8);
        ivec.push_back(9);
        for(vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
            *iter = 6; 
      
        return 0;    
    }

第四章    数组和指针
    理解指针声明语句时,从右向左阅读方便理解。
    预处理器变量NULL在cstdlib头文件中定义。
    C++提供void*指针,只与地址值有关。
    注意区分指向const对象的指针(const int *p)、const指针(int *const p)、指向const对象的const指针(const int *const p)。    观察const修饰的对象有助于区分他们。
    在4.2.5中谈到指针和typedef给出一例:
        typedef string *pstring;
        const pstring cstr;
        其中cstr变量是什么类型?一般错误地认为是指向const string的指针是因为把typedef当作文本扩展。typedef定义了pstring是一个指针,所以const修饰指针。    这里提到并不是故意抠字眼,在编写代码中,应该尽可能帮助人理解代码意图,当然一些定义习惯还是应该学习的。
        
    C++提供了新的内存管理方法,new和delete。需要注意在new申请内存使用结束后,应及时delete进行释放。
        在释放数组时,应该的操作:delete [] pia;
        
    多维数组中,很容易搞混的就是“指针的数组”和“指向数组的指针”了。
        int (*p)[4];    //指向拥有4个int元素数组的指针(pointer to an array of 4 ints)    我感觉英文注释更直观,在此一并附上
        int *p[4];    //int指针的数组,有4个元素(array of pointers to int)
        小技巧:后缀运算符的优先级高于单目运算符,即优先级[] > *,所以先和谁结合,也就确实了是数组还是指针。    具体可以参考http://learn.
        
    这一章跟C基本没有什么差别,所以也就不再列程序了


[ 本帖最后由 naruto01 于 2011-5-24 21:53 编辑 ]
2011-05-24 21:49
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
程序代码:
2011.5.25
第五章    表达式
    一般情况下,表达式的结果是右值。    int var; ++var; var++;    这里的两个表达式结果则为左值。
    在进行expr1 && expr2或者expr1 || expr2的判断时,会有“短路求值”,所以不能指望在一个逻辑判断表达式中,可以完成所有预期的操作。    大一看过《编程卓越之道 第二卷:运用底层语言思想编写高级语言代码》,在讲到短路求值时,好像意思是说不同的语言有不同的求值顺序。在C++ Primer中说到“总是先计算其左操作数,然后再计算其右操作数”。(中文版P132),应该仅指C++。
    
    位操作,不是循环移位,而是丢弃移出去的位,用0填充。
        原来在学习C语言过程中,就不是太注意。后来接触汇编,发现右移和左移代替一些乘除法的效率简直是惊人的,了解到补码这些概念后,在尝试把一段汇编代码翻译成C的时候,才意识到对“符号位”的操作存在空白。在P134中指出:“位操作符如何处理其操作数的符号位依赖于机器。”,最佳实践值得借鉴:“对于位操作符,由于系统不能确保如何处理其操作数的符号位,所以强烈建议使用unsigned整型操作数”。    
    
    复合赋值操作符,值得注意的是左操作数只计算了一次。    可能在一些小测试中,会用到这一点来坑害百姓哦。
    
    自增和自减操作符中,讲到了关于语言本身实现前置和后置操作的差别,前置操作更有效率。应该在没有差别时,优先使用前置操作。
    
    sizeof操作符返回的是一个对象或类型名的长度,单位是字节,返回值类型是size_t,编译时是常量。
    
    结合性中讲到的“左结合性”和“右结合性”。以前看书不是太肯定,这里尝试描述一下:从左到右就是左结合。
    
    不推荐死记硬背操作符的优先级,善于利用(),不过手边有一份优先级的表还是不错的选择。 ^ ^
    
    动态内存管理中,注意delete删除指针之后,该指针变成悬垂指针,应该及时将指针置0.
    
    类型转换中,有个const_cast,可以转换掉表达式的const性质,但书中提到,使用const_cast也总是预示着设计缺陷。
    
    
    本节不做程序为例。
    
第六章    语句
    在故意省略case后面的break语句是很罕见的,因此应该提供一些注释说明其逻辑。
    for循环语句,以前一直存在一个误区,以为必然会首先执行一次,类似do-while形式,其实是初始化语句(init-statement)结束后,求解判断条件(condition)。
    try/throw/catch在之前看的国内C教材,只在关键字中看到过,这里简单了解一下。主要有<stdexcept>中定义的若干标准异常类,定义了一个what的操作,没有任何参数,返回异常提供更详细的文字描述。
    
    预处理器调试时的常量:__FILE__    文件名、__LINE__    当前行号、__TIME__    文件被编译的时间、__DATE__    文件被编译的日期
    assert宏定义在cassert头文件,它的有效性取决于NDEBUG是否定义。使用assert来测试“不可能发生”的条件,如果assert宏求解条件表达式为false,则输出信息并且终止程序。
    
    对于异常处理这块,不是很感冒,所以也仅作了解。第一章程序已经使用了for、if,这里在此基础上仅仅简单地增加使用break。代码都会用到这几章的内容,是最普遍不过的基本组成部分了,所以也算是让自己好看点。多少复制点代码吧 - -#  唯一有价值的感觉就在注释的那句话。真不好意思。之后章节将只提供代码片段,重点快来咯。
    
    //code by naruto01
    #include <iostream>
    int main()
    {
        for(int i = 1; i <= 10; ++i)
            if((i % 2) != 0)
                std::cout << "Hello,World!" << std::endl;
            else if(7 == i)    //防止误写成i = 7的好办法
                        break;
        return 0;
    }    
2011-05-25 22:53
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
to fz19910125:用您都太抬举我了。  我们一起加油吧!
to W139307:谢谢你的支持。不过用搜索引擎就会发现分享学习经验的人大大的哦。
程序代码:
2011.5.26    
第七章    函数
    在C++中,使用引用形参则更安全和更自然。
    应该将不需要修改的引用形参定义为const引用。
    C++程序员倾向通过传递指向容器中需要处理的元素的迭代器来传递容器。
    完整main函数定义:
        int main(int argc, char **argv) {..}
    return语句用于结束当前正在执行的函数,并将控制权返回给调用此函数的函数。
    注意不要返回局部变量的引用。
    返回引用的函数返回一个左值。
    递归函数需要注意必须定义一个终止条件。
    
    如果有一个形参具有默认实参,那么它后面所有的形参都必须有默认实参,所以默认实参只能用来替换函数调用缺少的尾部实参。
    通常应在函数声明中指定默认实参,并将该声明放在合适的头文件中。
    如果在函数定义的形参表中提供默认实参,包含该函数定义的源文件中调用该函数时,默认实参才有效。
    
    应把一些简单的销操作定义为inline函数。    容易理解操作目的、方便修改、代码重用
    内联说明对于编译器来说只是一个建议,可以被忽略。
    内联函数应该在头文件中定义。
    
    类的成员函数其函数原型必须在类中定义。
    编译器隐式地将在类内定义的成员函数当作内联函数。
    类的成员函数可以访问该类的private成员。    这句话需要注意,是访问该类的成员,则意味只要两个对象属于相同的类,则可以访问对方的private成员。
        验证代码class test {
                            int i;
                            public :
                                void copy(test &b)
                                    { i = b.i; }
                                void set(int m)
                                    { i = m; }
                                void print()
                                    { cout << i << endl; }            
                        };
    每个成员函数(static函数除外)都有一个额外的、隐含的形参this。
    const成员函数的this是const指针,不会修改其成员数据。声明方式为一般函数声明后增加 constbool same_isbn(const Sales_item &rhs) const
    构造函数和类同名,而且没有返回类型,完成创建类类型对象时的初始化操作。
        可以有多个构造函数。
        例子:Sales_item(): units_sold(0), revenue(0.0) { }    //Sales_item为定义好的一个类    units_sold是unsigned的类成员    revenue是double的类成员
            在冒号和花括号之间的代码称为“构造函数的初始化列表”,每个成员后面括号中的是初始值。
        如果没有一个类显式定义的构造函数,编译器将自动为这个类生成默认构造函数。    注意这点与书上表达的不同。
        
    重载函数需要注意的是区别函数是否重载在于形参的个数和形参的类型。书中对重载的步骤以及实参类型转换带来的细节操作进行了讨论。
        仅当形参是引用或指针时,形参是否为const才有影响。
    
    指向函数的指针中,指向不同函数类型的指针之间不存在转换。
    指针调用函数可以(*p)(参数)或者p(参数),在把函数指针做形参时,也有对应的两种方式。    一般这个函数叫做回调函数(callback)。
    当函数返回指向函数的指针时,最佳方法是从声明的名字开始由里而外的理解。比如int (*ff(int))(int*, int);  则声明了ff(int),其返回int (*)(int*, int)的指针。typedef可以简化。    以前看过一个关于指针的文章,在最后出题时,就刁钻地出这个,当时感觉相当怪异。    
    函数的指针类型必须与重载函数的一个版本精确匹配。
    
    写到这里,我发现竟然用了2个小时的时间,其中也有自己写了些小程序来验证一些想法。在学习过程中,应该善于让编译器来帮我们验证一些问题。
2011-05-26 18:59
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
现在已经看到第13章 复制控制。开始感觉比较吃力,希望自己可以坚持住。  在407页13.1.2上面一句,按照我的理解书上错了。网上查找资料,也没有提及。我的分析如下:
程序代码:
Sales_item item = string("9-999-99999-9");

Sales_item类有一构造函数:Sales_item(const string&)
如果这个构造函数被定义为explicit,那么上面语句的构造函数就不是显式的,应该初始化失败。对吧? 

 
书中代码注释是:This initialization is okay only if the Sales_item(const string&) constructor is not explocot
但是下面中文翻译出:如果构造函数是显式的,则初始化失败;如果构造函数不是显式的,则初始化成功。

希望有哪位朋友可以指点一下。
欢迎各位朋友对我学习中的一些错误提出批评和指导。非常感谢你们的关注!  
另外补充关于这个笔记的说明:我已经比较熟悉C,也之前看过一些国内的C++资料,大概也知道继承、重载等的概念,并且算是略读这本书,希望对C++有个权威、系统的了解。如果你感觉有点过于简略,那么也开始你的学习笔记之旅吧!
程序代码:
2011.5.27
第八章    标准IO库
    当一个类继承另一个类时,这两个类通常可以使用相同的操作。
    如果函数有基类类型的引用形参时,可以给函数传递其派生类类型的对象。
    wchar_t类型的标准输入对象是wcin;标准输出是wcout;而标准错误是wcerr。
    IO对象不可复制或赋值。
        只有支持复制的元素类型可以存储在vector或其他容器类型里。
        形参或返回类型不能为流类型。    如果想传递或返回IO对象,则必须传递或返回指向该对象的指针或引用。
    8.2.2给出代码中while(cin >> ival, !cin.eof())    解释下逗号操作符的求解过程:首先计算它的每一个操作数,然后返回最右边操作数作为整个操作的结果。
    flush操纵符不添加任何字符刷新流。 ends操纵符插入null。    endl输出一个换行符。
    
        如果程序崩溃,则不会刷新缓冲区,所以使用endl是个良好的习惯。
    使用tie函数可以将输入流和输出流绑在一起,任何读输入流的尝试都将首先刷新其输出流关联的缓冲区。
        例如cin.tie(&cout); ostream *old_tie = cin.tie(); cin.tie(0);
    IO标准库使用C风格字符串作为文件名。
        在尝试打开新文件之前,必须先关闭当前的文件流。
        如果遇到文件结束符或其他错误,将设置流的内部状态,以便之后不允许再对该流做读写操作。即使关闭流也不能改变流对象的内部状态。而调用clear后,就像重新创建了该对象。
        ifstream infile;
        ofstream outfile;
        infile.open("in");
        outfile.open("out");
        //通常检查打开是否成功,是个好习惯
        if(!infile && !outfile) {
            cerr << "error: unable to open input or output file: " << endl;
            return -1;
        }
        
        infile.close();    //关闭文件流
        infile.clear();    //重置流状态
        infile.open("next");
        
    以binary模式打开的流则将文件以字节序列的形式处理,而不解释流中的字符。
    以out模式打开的文件会被清空。如果要保存文件中已存在的数据,唯一方法是显示地指定app模式打开。
    ofstream outfile("file", ofstream::app);
    
    stringstream提供的转换或格式化:
        该对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。
        int val1 = 512, val2 = 1024;
        ostringstream format_message;
        //format_message内容:val1: 512\nval2: 1024\n
        format_message << "val1: " << val1 << "\n"
                                     << "val2: " << val2 << "\n";
        //自动将数值型数据的字符表示方式转换为相应的算术值
        istringstream input_istring(format_message.str());
        string dump;
        input_istring >> dump >> val1 >> dump >> val2;    //一般情况下,使用输入操作符读string时,空白符将会忽略(这里补充下空白符的概念:空格、制表符、垂直制表符、回车符、换行符和进纸符)
        
2011-05-28 01:26
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
程序代码:
2011.5.28
第九章    顺序容器
    容器容纳特定类型对象的集合。    
    标准库中的三种顺序容器:vector、list、deque
    使用顺序容器需要包含头文件:#include <vector> <list> <deque>
    将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同。
        使用迭代器时,不要求容器类型相同。容器内的元素类型也可以不相同,只要它们相互兼容。
        指针就是迭代器。
    元素初始化式必须是可用于初始化其元素类型的对象的值。
    初始化,元素类型必须是内置或复合类型,或者是提供了默认构造函数的类类型。
        接受容器大小做形参的构造函数只适用于顺序容器,而关联容器不支持这种初始化。
    除了引用类型外,所有内置或复合类型都可做元素类型。
    除输入输出(IO)标准库类型以及auto_ptr类型之外,所有其他标准库类型都是有效的容器元素类型。
        特别地,容器本身也满足上述要求。
    在指定容器元素为容器类型时,必须使用空格:vector< vector<string> > lines;
    
    只有vector和deque容器提供两种重要的运算集合:迭代器算术运算、除了==和!=之外的关系操作符来比较两个迭代器。(==和!=这两种关系运算符适用于所有容器)。    不理解迭代器相加有什么实际意义。网上查资料,也没有什么结果。
    C++使用一对迭代器标记迭代器范围,这个范围是左闭合区间,即[beg, end),end被作为哨兵。
    在使用迭代器编写程序时,必须留意哪些操作会使迭代器失效。
    在逆序迭代器上做++运算将指向容器中的前一个元素。
    所有顺序容器都支持push_back操作。
    在容器中添加元素时,系统是将元素值复制到容器里。
    当编写循环将元素插入到vector或deque容器中时,程序必须确保迭代器在每次循环后都得到更新。
    假设所有迭代器失效是最安全的做法。
    比较的容器必须具有相同的容器类型,而且其元素类型也必须相同。
    C++语言只允许两个容器做其元素类型定义的关系运算。
    resize操作指定的新长度小于当前容器长度,则该容器后部的元素会被删除。
    back操作返回容器的最后一个元素的引用。
    erase(p)删除迭代器p指向的元素,返回指向被删除元素后面的元素。
    在不同(或相同)类型的容器内,元素类型不相同但是相互兼容,则其赋值运算必须使用assign函数。
    assign操作首先会删除容器内原来存储的所有元素。
    swap操作不会删除或插入任何元素,而且保证在常量时间内实现交换,迭代器不会失效。
    capacity操作获取在容器需要分配更多的存储空间之前能够存储的元素总数。
    reserve操作告诉vector容器应该预留多少个元素的存储空间。
    
    通常来说,除非找到选择使用其他容器的更好理由,否则vector容器都是最佳选择。
    使用迭代器,而不是下标,并且避免随机访问元素,可以很方便地将程序从使用vector容器修改为使用list容器。
    可讲string类型视为字符容器。
    
    适配器是使一事物的行为类似于另一事物的行为的一种机制。    说白了就是一般是站着尿的,也可以蹲着尿  - -#
    栈容器适配器中pop操作删除栈顶元素,但不返回其值。top操作返回栈顶元素的值,但不删除该元素。
    
    在容器中添加或删除元素可能会使已存在的迭代器失效。
2011-05-29 00:36
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
to 爱德华:都是摘抄书上的  - -#  不过还是谢谢
程序代码:
2011.5.29
第10章    关联容器
    关联容器通过键(key)存储和读取元素。
    map的元素以键-值(key-value)对的形式组织。
    set仅包含一个键。
    pair类型在utility头文件中定义。
    对于pair类,可以直接访问其数据成员,分别命名为first和second。
    容器元素根据键的次序排列。
    
    使用map对象,包含头文件map。
    它的键不但有一个类型,而且还有一个相关的比较函数。
    键类型必须定义<操作符,而且该操作符应能“正确地工作”。
    value_type是存储元素的键以及值的pair类型,而且键为const。
    
    用下标访问不存在的元素将导致在map容器中添加一个新元素。
    map::insert(e)    如果改建在map类型中已存在,则保持不变。返回一个pair类型对象以及一个bool类型的对象,表示是否插入了该元素。
        下标操作符副作用:不必要的初始化。
        含有一个或一对迭代器形参的insert函数版本并不说明是否有或有多少个元素插入到容器中。
    不能依靠下标访问来确认该元素是否存在。
    
    使用set对象,包含头文件set。
    set不支持下标操作符,而且没有定义mapped_type类型。
        value_type不是pair类型,而是与key_type相同的类型。
    set容器的每个键都只能对应一个元素。
    在获得指向set中某元素的迭代器后,只能对其做读操作。
    
    multimap和multiset分别用的是map和set头文件。
    multimap不支持下标运算。
    带有一个键参数的erase版本将删除拥有该键的所有类型,并返回删除元素的个数。
    
    TextQuery类的设计将将在下篇仿着实现。


[ 本帖最后由 naruto01 于 2011-5-30 17:46 编辑 ]
2011-05-29 22:57
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
to 雨的帝国:谢谢
程序代码:
2011.5.30
    TextQuery类的实现
    主要思路:现将输入文件用vector<string>保存副本,文件的每一行都是该vector对象的一个元素;然后构建map容器,其value_type为string(对应文件中一个单词)和set容器(该单词出现的行号,自动排序)。
    这里照抄下书上给出的TextQuery类定义:
    calss TextQuery {
    public:
        typedef std::vector<std::string>::size_type line_no;    //下标对应相应行号
        //完成上述主要思路
        void read_file(std::ifstream &is)
            { store_file(is); build_map(); }
        //获得一组所查找的单词出现的行号
        std::set<line_no> run_query(const std::string &) const;
        //输出出现该单词的每一行
        std::string text_line(line_no)    const;
    private:
        //保存副本
        void store_file(std::ifstream &);
        //构建map容器
        void build_map();
        //文本映像
        std::vector<std::string> lines_of_text;
        //map容器
        std::map< std::string, std::set<line_no> > word_map;
    };
    下面对每一个成员函数进行实现:
    1.存储输入文件
    void TextQuery::store_file(ifstream &is)
    {
        string textline;
        while(getline(is, textline))
            lines_of_text.push_back(textline);
    }
    2.建立map
    void TextQuery::build_map()
    {
        for(line_no num = 0; num != lines_of_text.size(); ++num)
        {
            istringstream line(lines_of_text[num]);
            string word;
            while(line >> word)
                word_map[word].insert(num);
        }
    }
    3.查询操作
    set<TextQuery::line_no> TextQuery::run_query(const string &query_word) const
    {
        //进行查询操作,不会发生修改,所以使用const_iterator
        //通过find进行查找
        map<string, set<line_no> >::const_iterator site = word_map.find(query_word);
        
        if(word_map.end() == site)
            return set<line_no>();    //查询单词没有找到,书上直接建立一个空set返回。
        else
            return site->second;
    }
    4.输出单词出现行的内容
    string TextQuery::text_line(line_no line) const
    {
        if(line < lines_of_text.size())    //检查行数是否合法
            return lines_of_text[line];
        throw std::out_of_range("line number out of range");
    }
    
    TextQuery类的使用代码就不实现了。
    在这次练习中,印象最深刻的是对作用域的感受。在十二章,有专门讲解作用域一节。


[ 本帖最后由 naruto01 于 2011-5-30 17:49 编辑 ]
2011-05-30 17:45
naruto01
Rank: 4
等 级:业余侠客
帖 子:103
专家分:280
注 册:2011-5-23
收藏
得分:0 
程序代码:
2011.5.31
第11章    泛型算法
    “泛型”指的是它们可以操作在多种容器类型上。
    算法有着一致的结构,了解算法的设计可使我们更容易学习和使用它们。
    泛型算法本身从不执行容器操作,只是单独依赖迭代器和迭代器操作实现。
    算法从不直接添加或删除元素。
    包含头文件#include <algorithm>
    在写容器元素的算法中,必须确保算法所写的序列至少足以存储要写入的元素。
        对指定数目的元素做写入运算,或者写到目标迭代器的算法,都不检查目标的大小是否足以存储要写入的元素。
    确保算法有足够的元素存储输出数据的一种方法是使用插入迭代器。
    谓词是做某些检测的函数,返回用于条件判断的类型,指出条件是否成立。
    
    插入迭代器是一种迭代器适配器,带有一个容器参数,并生成一个迭代器,用于在指定容器中插入元素。
        back_inserter、front_inserter、inserter
    
    可以比较两个istream迭代器是否相等,而ostream迭代器则不提供比较运算。
        下面给出一个流迭代器常用的例子:
            istream_iterator<int> cin_it(cin);    //在创建时,可直接绑定到一个流上。
            istream_iterator<int> end_of_stream;    //创建时不提供实参,则该迭代器指向超出末端位置。
            
            ostream_iterator<Sales_item> output(outfile, " ");    //分隔符必须是C风格字符串
    提供输入操作符(>>)的任何类型都可以创建istream_iterator对象。
    流迭代器的重要限制:
        不可能从ostream_iterator对象读入,也不可能写到istream_iterator对象中。
        一旦给ostream_iterator对象赋了一个值,写入就提交了。此外,每个不同的值都只能正好输出一次。
        ostream_iterator没有->操作符。
        
    sort调用完成后,重复输入的数就会相邻存储。
    
    流迭代器不能创建反向迭代器。
    反向迭代器用于表示的范围,和普通迭代用于表示的范围不对称。
    
    迭代器种类:输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器
    除了输出迭代器,其他类别的迭代器形成了一个层次结构:需要低级类别迭代器的地方,可使用任意一种更高级的迭代器。
    关联容器的键是const对象,因此关联容器不能使用任何写序列元素的算法。
    在处理算法时,最好将关联容器上的迭代器视为支持自减运算的输入迭代器,而不是完整的双向迭代器。
    对于每一个形参,迭代器必须保证最低功能。
    
    算法最基本的性质是需要使用的迭代器种类。
    四种形式:
        alg(beg, end, other parms);
        alg(beg, end, dest, other parms);
        alg(beg, end, beg2, other parms);
        alg(beg, end , beg2, end2, other parms);
        1)dest形参是一个迭代器,用于指定存储输出数据的目标对象。
            算法假定无论需要写入多少个元素都是安全的。
            通常要使用插入迭代器或者ostream_iterator来。
                ostream_iterator则实现写输出流的功能,无需考虑所写的元素个数。
        2)beg2视为第二个输入范围的首元素
            算法假定以beg2开始的范围至少与beg与end指定的范围一样大
        
    重新对容器元素排序的算法使用<操作符,则第二个重载版本带有一个额外的形参,表示用于元素排序的不同运算。
    检查指定值的短发默认使用==操作符,带有谓词函数形参的算法,名字带有后缀_if。
    无论算法是否检查它的元素值,都可能重新排列输入范围内的元素。将元素写到指定的输出目标,在名字中添加后缀_copy。


[ 本帖最后由 naruto01 于 2011-5-31 23:42 编辑 ]
2011-05-30 17:45
快速回复:C++学习笔记,已结束
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.029370 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved