C++ Primer 3rd 读书笔记2/2

来源:互联网 发布:feel软件增高 编辑:程序博客网 时间:2024/05/16 15:51

第六章    抽象数据类型

1.    顺序容器主要有:list、vector和deque. 容器中的每个元素都被初始化为“与该类型相关的缺省值”。因此,对于含有自定义的数据类型,该类型必须含有默认的构造函数。

       Capacity()函数返回容器的容量,即在容量增加前还能存储多少元素。

       Size()函数返回容器当前含。的个数。    

容器详解:

       Vector:表示一段连续的的内存区域,随机访问效率高,插入、删除效率低。Vector能够自动扩充容量,对于常用的数据类型:int、string,使用vector比list性能更好。

       Deque:与vector相同,但是提供对首元素的插入和删除提供特殊支持。

List:非连续的内存区域,通过双向链表实现,插入、删除效率高,随机访问效率低。List插入元素时只是简单的双链表元素插入,容量自动增加1。

顺序容器使用准则:

1.    要随机访问一个容器使用vector比list好

2.    已知要存储元素的个数,使用vector比list好

3.    如果我们需要的不只是在容器两端插入和删除元素,而是在任意位置插入、删除,使用list比vector好。

4.    除非我们需要在容器首部插入和删除元素,否则vector比deque好。

2.    关联容器主要有:map和set。Map是key-value,set是单值。Map和set只能存放唯一的一个key,multimap和multiset能够存放多个相同的key。

3.    vector、list、deque常用函数:

       1.添加元素:push_back。List和deque还支持push_front。

       2.插入元素:insert(pos,item);

       3.查询元素位置的iterator:find(begin,end,item);

       4.删除元素:eraser(iterator)

       5.删除末尾元素:pop_back()

       6.容器赋值:slist1=slist2(slist1含有10个元素,slist2含有20个元素,现在slist1含有20个元素,并且全部被改成slist2的元素)。Slist.swap(slist2);与slist1=slist2;类似,但是现在slist2含有slist1中的10个元素。

4.    迭代器iterator提供了一种一般化的方法,对顺序和关联容器进行连续访问。每个容器类型都提供begin和end成员函数,分别返回执行容器第一个和最后一个元素的iterator。

       容器的迭代:

For(iter=container.begin();iter!=container.end();++iter){doSomething(*iter);}

5.       string类常用函数:

1.      查找函数str.find(substr)返回匹配substr的第一个字符的索引位置;str.find_first_of(substr)查找与被搜索字符串中任意一个字符匹配的第一次出现,并返回索引位置。Str.rfind(substr)从后查询并返回位置索引。Find_first_not_of()、find_last_of().

2.      删除:erase(pos,num)。从pos开始,删除num个字符。

3.      替换:replace

4.      插入:insert

5.      连接字符串:append、assign

6.      交换:swap

7.      比较:compare

6.       关联容器的使用、使用关联容器实现:栈、队列

第七章    函数

1.    函数被inline修饰后,该函数在编译期间便被展开。不使用inline修饰,在运行时才被调用。

2.    无参函数可以不写形参或者使用void。

3.    所有的函数都使用程序运行中分配的存储区。该存储区与该函数相关联,直到函数结束为止。在存储区中,系统为每个函数的参数分配独立的存储区,所谓的参数传递是值用函数的实参来初始化该存储区中的形式参数。C++中默认的初始化方法是把实参的值拷贝到形参的存储区中,称之为按值传递。函数操纵访问的是形参,即实参的拷贝,因此对实参不造成影响。

4.    引用参数:把参数声明成引用,实际上改变了缺省的按值传递的机制。函数接受到的是实参的左值,能够改变它的值或者取它的地址。

       使用引用参数的三种情况:

1.       需要改变参数的值

2.       向主调函数返回额外的结果

3.       向函数传递大型类对象(传值需要赋值,性能不高)

如果希望传递的实参不能被修改,可以声明为const型。

理解:交换两个指针:

Void ptrswap(int *&v1,int *&v2)

{

Int *tmp = v2;

V2 = v1;

V1 = tmp;

}

Int *&v表示:v是一个引用,他引用的是一个指向int类型的指针。

5.    指针参数:把参数声明成指针,函数接受的是实参的地址,能够改变实参的值。相比于引用,指针可以指向不同的对象。因此,在使用指针参数时,首先需要判断指针是否为0,能否解引用。

6.    引用参数和指针参数的对比:

       引用参数允许我们在改变实参值的同时,实现用法的直观性。如果一个参数可能需要在函数中指向不同的对象,或者这个参数可能不指向任何对象,必须使用指针参数。

7.       数组参数:数组永远不会按值传递,传递的是第一个元素的指针。因此void test(int [])int test(int *)是等价的。数组参数传递第一个元素的指针,因此数组的长度没有被表示,可以使用int test(int &array[10])表示接受参数为长度为10的数组。

8.    缺省参数:int test(int a =10);调用test时,我们可以为test提供参数,也可以不提供。如果提供,则提供值覆盖缺省值;不提供,使用缺省值。

9.    省略号(…)表示函数的参数可以有0个或者多个。

10.  返回值缺省情况下返回值是按值传递的,返回给调用函数的是被调用函数值的拷贝。返回类型按值传递可以通过返回引用或者指针改变。这里特别注意的是,返回引用或者指针可能犯的错误:

       1.    返回一个指向局部对象的引用或指针。局部对象随着函数的调用就结束。

       2.    函数返回一个左值。返回左值能够对左值进行修改,为防止对引用返回值的无意修改,应返回constconst int &test();

11.  直接或者间接调用自己的函数成为递归函数。递归函数必须有一个停止条件。

12.  C++采用链接指示符exttern “c”调用C语言写的程序。

13.  命令行参数:int main(int argc, char** argv)或者int main(int argc,char* argv[])其中,argc包含命令行选项的个数,argv表示命令行参数。Argv[0]表示当前的命令,argv[1]到argv[argc-1]表示传进来的命令行参数。

14.  指向函数的指针:int(*p)(const string &,const string &)

       返回类型为指针的函数:int*p(const string &,const string &)

       当函数名没有被调用操作符修饰时,会被解释成为该类型函数的指针。例如:

int lexicoCompare(const string &)中,单lexicoCompare表示:

int(*) (const string &)

使用&lexicoCompare和直接使用lexicoCompare的效果一样,都得到函数指针。

Int (*lex) (const string &) = lexicomCompare;  //初始化

Lexicompare(str);  //函数调用

Lex(str);         //指针调用

(*lex)(str);       //指针显示调用

第八章    域和生命周期

1.全局域中定义的对象,如果没有显示的初始化,默认初始化为0.

2.extern用于变量声明,如果不显示初始化,不引起内存分配。

3.静态对象只在首次初始化时初始化一次。静态变量未经显示初始化的自动被初始化为0.

4.动态分配的对象位于空闲存储区,使用new分配的对象位于此处,且分配出来的对象没有名字,new返回的不是对象,而是对象的指针。

第九章    重载函数

1.在C++中,返回类型不同,参数名和参数列表相同的两个函数会在编译器报错重载区别的是参数类表,参数类型,参数数量、顺序。使用typedef不引入一个新类型,在重载的时候需要注意。

2.对于按值传递的参数,constvolatile修饰参数不引起重载;但是对于传址的指针或者引用时,需要考虑constvolatile对重载的影响。即:

       Void f(int)与void(constint)是同一函数;

       Void f(int *)与void f(const int *)是重载函数。

3.重载函数集合中的全部函数都应该在同一个域中声明。不同的名字空间成员的函数不能相互重载。

4.函数重载解析的步骤:

       1.去顶函数调用考虑的重载函数的集合;

       2.从重载函数结合中选择函数,该函数可以在给出实参个数和类型的情况下调用指定的实参进行调用。

       3.选择与调用最匹配的函数。

第十章    函数模板

1.函数模板提供一种用来自动生成各种类型函数实例的算法。如下:

       Template <class Type>

       Type min(Type a, Type b)

       {

       Returna<b ? a:b;

}

2.在全局域中声明了与模板参数,例如Type相同的对象名,该对象名将被隐藏。

3….

第十一章     异常处理

1.      异常是程序可能检测到的,运行时刻不正常的情况,位于程序的正常函数之外,可以被捕获,处理。

2.      抛出异常:throw Exception();

3.    捕获异常:try{}catch(exception){}

第十二章     泛型算法

待看

第十三章     类

1.       在C++中,类中的非静态成员变量不允许显示初始化。与Java有区别哈!

2.       C++中的访问限定符:

a)       Public:程序的任何地方都能访问

b)       Protected:父类及其子类可以访问

c)       Private:本类成员函数和友元函数能够访问

3.       友元函数允许一个类授权其他的函数访问他的非公有成员。友元函数以friend开头。

4.       类声明:class Screen;

5.       “.”与类对象和引用连用,“->”与指针连用。

6.       对象作为函数参数,默认采用按值传递。p->fun()ó(*p).height()

7.       每个类都有一个成员函数,多个成员变量。通过this指针可以实现不同类的实例调用不同的成员函数。

8.       在类体中定(.h文件)义的成员函数或者与类体在同一文件中实现的成员函数都自动默认为inline函数,不在类体或者类头文件中实现的成员方法,默认不是inline函数,但是可以通过inline关键字指定为内联函数。

9.       成员函数通过标记为const表明函数不修改类对象。例如:

Char get() const {return _t;}注意const位于函数头的结尾函数体的开始。如果是在类体之外定义的函数(在cpp中),定义(.cpp)和声明中(.h)都要加上const关键字。将一个修改类对象的函数声明为const是不合法的。

10.   声明为const的类只能调用const成员函数。构造函数和析构函数例外,非const类对象也可以调用。

11.    静态成员变量每个类只有一份,为所有类对象共享。静态成员的初始化不能放在头文件中,而应放到包含非inline函数定义中。静态成员函数如果定在函数体外,不用写static关键字。静态成员函数没有this指针。

12.    嵌套类是在类中定义的一个成员类。

第十四章     类的初始化、赋值和析构

1.      成员初始化列表在类定义而不是类声明处调用,用于初始化成员变量,放在构造函数头和函数体之间,使用“:”开始。初始化列表在初始化阶段初始化成员变量。构造函数的执行分为初始化阶段和赋值阶段。构造函数在赋值阶段进行成员变量的赋值,在完成“初始化”这方面,效率低于初始化列表。

2.      对于内置数据类型的成员变量,使用初始化列表和构造函数效率相同。但是需要注意的是对于const和引用这两个需要在定义是初始化的修饰的变量,必须在成员初始化的时候进行初始化,而不能在构造函数中进行赋值(初始化)。

3.      为构造函数指定实参有三种形式:

a)       Accountacc1(“haha”);

b)       Accountacc2=Account(“haha”);

c)       Accountacc3=”haha”;//仅仅适应于一个参数的情况。Explicit用于进制这种初始化的方法。Explicit通知编译器不要提供隐式转换。Explicit只能用于构造函数。

4.      构造函数不能用const和volatile进行声明,因为只有const类对象才能访问const函数数。

5.      拷贝构造函数:用一个类对象初始化另一个类对象称之为缺省按成员初始化拷贝构造函数在按成员初始化时调用。拷贝构造函数以类对象的引用作为参数:const Account &ac。深拷贝字符串:_str1= new char[strlen(str)+1];strcpy(_str,src_str);

6.      析构函数用于释放对象占用的资源。显示的调用析构函数。Ptr->~Image();

第十五章     重载操作符和用户定义的转换

1.       重载操作符:string& operator=(const string &){};

2.       不能被重载的操作符:“:: . *  ?  :”

第十六章     类模板

1.    类模板:

Template<class Type>

Class Queue

{

  Public:

      Queue();

      ~Queue();

}

//使用

Queue<int> qi;

第十七章     类继承和子类型

1.       继承语法:subclass:access-levelbaseclass;

例如:classMan:public People{};

2.       子类继承父类前,父类必须已经进行了定义。

class Query;  classNameQuery:publicQuery{};     错误

class Query; class NameQuery; 这样进行声明

3.       派生类可以调用父类的函数或者属性,但是两种不能重名,否则发生隐藏。

4.       不使用virtual关键字,对象调用的是该对象静态类型的方法。Base b = new Sub(); b.play();//调用的是Base的play();

通过virtual关键字,对象调用的是该对象动态类型的方法。Base b = new Sub(); b.play();//调用的是Sub的play();

Virtual 必须放在类声明中,在类定义中不用写virtual关键字。

5.       纯虚函数 virtual int fun()=0;提供子类可以改写的接口,本类不用实现。包含一个或者多个纯虚函数的类称之为抽象基类,不能实例化对象。

6.       Base是抽象基类,Sub继承Base。则:

Base *b = newSub();

b->fun();//通过虚拟机制调用Sub::fun(),在运行时刻调用

b->Base::fun();//静态调用Base::fun(),在编译时刻调用

第十八章     多继承和虚拟继承

1.      多继承:class Bear: pulbic Zoo,public Animal{};基类构造函数被调用的顺序以类派生表中定义的顺序为准。

2.      虚拟继承:虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下:

class A

class B1:public virtual A;

class B2:public virtual A;

class D:public B1,public B2;

虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要因为这样只会降低效率和占用更多的空间。

3.      常见面试题:


如果对这四种情况分别求sizeof(a),  sizeof(b)。结果是什么样的呢?下面是输出结果:(在vc6.0中运行)
第一种:4,12 第二种:4,4第三种:8,16(8+4+4) 第四种:8,8

在虚拟继承中,子类包含父类的全部,并且使用虚类指针(大小为4)指向这些内容。非继承父类的虚函数使用大小为4的指针指向。对于数据成员而言,子类一定含有父类的数据成员,如第四种情况。

因为每个存在虚函数的类都要有一个4字节的指针指向自己的虚函数表,所以每种情况的类a所占的字节数应该是没有什么问题的,那么类b的字节数怎么算呢?看“第一种”和“第三种”情况采用的是虚继承,那么这时候就要有这样的一个指针vptr_b_a,这个指针叫虚类指针,也是四个字节;还要包括类a的字节数,所以类b的字节数就求出来了。

虚函数指向的vtpr,代表的是一个表,无论多少个虚函数,都是4.

子类继承父类的虚函数,因此也有一个父类的vptr。然后是自己的vptr,无论自己多少个虚函数,都是4.

C++ Primer 4rd 笔记整理中的知识点

1.    遍历vector的两种方式:

For (vector<int>::size_type i=0;i!=ivec.size();++i)

{

    Ivec[i]

}

For (vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)

{

    *iter;

}

2.    友元包括友元类和友元函数。

0 0
原创粉丝点击