您的位置:首页 > 编程语言 > C语言/C++

C++ Primer学习系列(3):函数/标准IO库/顺序容器

2016-07-29 00:00 274 查看
7 章 函数

7.1
函数调用操作符 ():操作数是函数名和一组(可能为空)由逗号分隔的实参
实参必须具有与形参类型相同、或者能隐式转换为形参类型的数据类型
函数的返回类型:可以是内置类型、类类型、复合类型(如引用或指针)、 void类型(不返回任何值);函数不能返回另一个函数或者内置数组类型,但可以返回指向函数或数组的指针
注意:函数必须指定返回类型
形参是一个变量,其作用域为整个函数;实参是一个表达式,用于对形参进行初始化
7.2
形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值,如果形参为引用类型,则它只是实参的别名
指针初始化规则:可将指向 const对象的指针初始化为指向 const或非 const对象,但不可以让指向非 const对象的指针指向 const对象。对指针形参,也要遵循这个规则
非引用的非 const形参:既可传递 const实参,也可传递非 const的实参,因为初始化复制了初始化式的值
非引用的 const形参:在函数中该形参值不可改变,传递的实参值可以是 const对象也可以是非 const对象
让函数修改实参的值:使用指针或引用形参,但是如果使用引用形参只是为了避免复制实参,而不是为修改实参,则应将形参定义为 const引用
非 const的引用形参:只能与完全同类型的非 const对象关联。不能传递 const实参,不能传递右值、常量或需要转换类型的对象,因为 非 const的引用形参只能与完全同类型的非 const对象关联
指向指针的引用: int *&v1;
通常,函数不应该有 vector或其他标准库容器类型的形参,调用含有非引用 vector形参的函数会复制 vector的每一个元素。 C++倾向于传递指向元素的迭代器来传递容器
数组形参:数组作形参时,编译器不会检查数组的长度,故通常更倾向于传递指向数组第一个和最后一个元素的下一个位置的指针
不需要修改数组形参的元素时,应该定义成指向 const对象的指针
void f(const int*) {/*...*/}
通过引用传递数组:这时数组形参、数组实参的大小都会被检查
应用指针形参的情况:函数体不依赖于数组的长度;可以用任意长度的实参数组来调用函数
应用引用形参的情况:函数体中依赖数组的长度是安全的
省略符形参:这是为了与 C兼容。对于 C++程序,只能将简单数据类型传递给省略符形参,因为传递类类型对象时一般不能正确复制。省略符暂停了类型检查机制。常在无法知道实参类型和数组时用。
Void foo(parm_list, ...);
void foo(parm_list...);
void foo(...)
7.3
主函数 main的返回值:其值的意义依赖于机器。为了独立于机器, <cstdlib>中定义了两个预处理变量 EXIT_FAILURE和 EXIT_SUCCESS
返回非引用类型:在调用的地方复制返回对象的值
返回引用类型:在调用的地方没有复制返回值,而是返回对象本身。注意返回的引用是左值,因此这样的函数调用可放在赋值操作会的左边
千万不要返回局部对象的引用。确保返回引用安全的一个方法是:请自问,这个引用指向是函数中的局部对象还是函数之前存在的对象?
同样千万不要返回指向局部对象的指针
7.4
函数原型:返回类型、函数名、形参类型列表
函数声明最好放在头文件中:定义函数的源文件应包含声明该函数的头文件
默认实参:即为形参定义的默认值。若一个形参有黑夜实参,则后面所有的形参都必须有默认实参
通常应在函数声明中指定默认实参,并将该声明放在头文件中
7.5
static局部对象:在整个程序中有效,而不仅是其所在函数内;仅初始化一次
7.6
inline函数:可以避免函数调用的开销。注意 inline对编译器来说只是一个建议,编译器可以选择忽略这个建议
内联函数适用性:适用于优化小的、只有几行的而且经常被调用的函数。大多数编译器都不支持递归函数的内联
内联函数定义最好在头文件中;而如果在各个源文件中定义一个内联函数,则必须保证各个定义都是一样的
7.7
函数原型必须在类中定义,而函数体既可在类中也可在类外定义,编译器隐式地将在类中定义的成员函数当作内联函数
每个成员函数都有一个额外的、隐含的形参将该成员函数与调用该函数的类对象捆绑在一起
this指针:是隐含的形参,代表调用成员函数的类对象
const成员函数:函数声明的形参表后跟 const,指示隐含的 this形参将指向 const对象
class Sales_item{
public:
double avg_price() const; //const成员函数
bool same_isbn(const Sales_item &rhs) const
{ return isbn==rhs.isbn;}
private:
std::string isbn;
unsigned units_sold;
double revenue;
};
const对象、指向 const对象的指针或引用:只能用于调用其 const成员函数,不能调用其非 const成员函数
构造函数:没有返回类型,与类同名
构造函数的初始化列表:为类的一个或多个成员指定初值
Sales_item():units_sold(0),revenue(0.0){ }
合成的默认构造函数:由编译器创建的默认构造函数,它根据对象是在全局创建还是在局部创建来初始化类中的成员(局部对象的内置类型成员无初始化),因此它一般适用仅包含类类型成员的类,有内置类型成员时,最好显示定义构造函数
7.8
重载函数 overloaded function:在同一作用域中的两个同名,而形参表不同的函数
const引用形参与非 const引用形参是不同类型的;指向 const类型的指针形参与指向非 const对象的指针形参也是不同类型的
非引用的形参:在重载时 const的与非 const的非引用形参视为同一种类型,因为实参采用复制方式初始化形参,复制实参时并不考虑形参是否为 const
重载与作用域:在函数中局部声明的函数原型会屏蔽掉在全局作用域中声明的同名函数(包括重载的函数)。因为编译器先在作用域中检索名字声明,找到了就会使用这个名字,不再继续在外层作用域中寻找
注意:在 C++中,名字查找发生在类型检查之前
函数匹配与实参转换:精确匹配优于需要类型转换的匹配;具体优先级从高到低为精确匹配、通过类型提升实现的匹配、通过标准转换实现的匹配、通过类类型转换实现的匹配
在实际应用中,调用重载函数时应尽量避免对实参做强制类型转换:需要使用强制类型转换意味着所设计的形参列表不合理
无法将整型值传递给枚举类型的形参,但可以将枚举值传递给整型形参(是类型提升)
将引用形参或指针形参定义为 const来重载函数是合法的,因为编译器可以根据实参是否为 const确定调用哪一个函数
注意不能基于指针本身是否为 const来实现函数的重载,因为这时指针实参变量本身是以副本传递的
7.9
指向函数的指针:指针的类型由其返回类型和形参表确定
bool (*pf)(const string&,const string&);
指针的类型为 pf类型,常用 typedef简化定义
typedef bool (*cmpFcn)(const string&,const string&);
函数指针的初始化:
bool lengthCompare(const string&,const string&);
cmpFcn pf1=0;
cmpFcn pf2=lengthCompare; //函数名本身自动解释为指向函数的指针
pf1=lengthCompare;
pf2=pf1;
函数指针只能通过同类型的函数名、函数名引用、函数指针、 0值常量表达式进行初始化或赋值,通过指针调用函数时无需解引用
函数指针形参:有两种编写方式
void useBigger(const string&,const string&,bool(const string&,const string&));
void useBigger(const string&,const string&,bool (*)(const string&,const string&));
返回指向函数的指针:
int (*ff(int))(int *,int); //用 typedef就可以理解了
typedef int (*PF)(int*,int);
PF ff(int);
指向重载函数的指针:指针的类型必须与重载函数的一个版本精确匹配
extern void ff(vector<double>);
extern void ff(unsigned int);
void (*pf1)(unsigned int)==&ff; //用 &ff或 ff初始化都可以,效果一样
总结:
函数定义、参数传递、非引用形参、引用形参( const与非 const的)、指针形参、数组形参、 main函数的命令行选项、省略符形参、返回引用和指针、函数声明、默认实参、 static对象、内联函数、成员函数、 this指针、 const成员函数、构造函数初始化列表、重载函数、函数匹配、重载和 const形参、指向函数的指针、函数指针形参

8 章 标准 IO
8.1
<iostream>:istream,ostream,iostream
<fstream>:ifstream,ofstream,fstream
<sstream>:istringstream,ostringstream,stringstream
如果函数有基类类型的引用形参,则可以传递其子类型的对象
国际字符支持:相应的读写 wchar_t数据的流为上面九个类前加 w,标准输入 wcin,标准输出 wcout,标准错误 wcerr
IO对象不可复制或赋值
只有支持复制的元素可以存储在 vector或其他容器类型里,因此流对象不能存储在 vector或其他容器里
形参或返回类型也不能为流类型,但可以为指向它们的引用或指针
8.2
流的状态:状态值均为 strm::iostate类型,是机器相关的整型名
IO标准库的条件状态: strm::iostate,strm::badbit,strm::failbit,strm::eofbit,s.eof,s.fail(),s.bad(),s.good(),s.clear(),s.clear(flag),s.setstate(flag),s.rdstate()
每个 IO类还定义了三个 iostate类型的常量值 badbit,failbit,eofbit,分别表示相应的位模式:系统故障、读入无效数据、遇到文件结束符
8.3
操纵符: endl,ends,flush,unitbuf,nounitbuf
输入和输出绑在一起时,读输入流会刷新输出缓冲区, cin和 cout是绑在一起的
流的 tie函数:将两个流对象绑在一起
8.4
如果程序员需要重用文件流读写多个文件,必须在读另一个文件之前调用 clear清除该流的状态
为了向后兼容, C++中的文件名使用 C风格字符串,而不是 C++ string类型的字符串。一般把文件名保存为 string,然后调用 c_str()转化
文件模式: in,out,app,ate,trunc,binary,都是整型常量。以 out模式打开的文件会被清空,丢弃数据。从 8效果来看,为 ofstream对象指定 out模式行将于同时指定了 out和 trunc模式
打开模式的有效组合: out,out|app,out|trunc,in,in|out,in|out|trunc
8.5
stringstream特定的操作:
stringstream strm;
stringstream strm(s);
strm.str();
strm.str(s);
为了读取关联了字符串的 istringstream或 ostringstream对象,必须把该对象分解为若干个部分。如果读到数值型变量中,则要忽略所需数值周围的标号(如空格)
总结:
Io标准库、 IO对象不可复制或赋值、条件状态、文件模式

9 章 顺序容器
9.1
顺序容器: vector,list,deque
顺序容器适配器: stack,queue,priority_queue
容器类型常用默认构造函数,可达到最佳运行时性能
将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都要匹配
接受容器大小做形参的构造函数只适用于顺序容器,而关联窗口不支持这种初始化
容器的初始化:默认构造函数;初始化为另一容器的副本;初始化为一段元素的副本(两个迭代器或数组元素指针标示的范围);初始化为指定数目的元素
容器中的元素类型满足的约束:
( 1)元素类型必须支持赋值运算;元素类型的对象必须可复制
( 2)所有内置或复合类型都可用做元素类型
( 3)除 IO标准库类型、 auto_ptr类型外,所有其他标准库类型都可用做元素类型
9.2
vector和 deque的迭代器支持减法运算,加一个常量运算,关系运算( <,<=,>,>=),比较运算( ==,!=),自增和自减运算;而 list的迭代器不支持加法或减法,也不支持关系运算,只支持自增自减和比较运算
9.3
顺序容器的操作:添加元素、删除元素、设置容器大小、获取第一个和最后一个元素
容器定义的类型别名: size_type,iterator,const_iterator,reverse_iterator,const_reverse_iterator,difference_type,value_type,reference,const_reference
迭代器操作: begin(),end(),rbegin(),rend()
添加元素操作: push_back(t),push_front(t)只适用于 list和 deque容器 ,insert(p,t),insert(p,n,t),insert(p,b,e)
关键概念:容器元素都是要添加的元素的副本
所有容器类型都支持关系操作符来实现两个容器的比较
C++语言只允许两个容器做其元素类型定义的关系运算
容器大小的操作: size(),max_size(),empty(),resize(n),resize(n,t)
访问元素操作: c.back(),c.front(),c
及 c.at(n)则只适用于 vector和 deque容器
若下标无效,则 at(n)会抛出 out_of_range异常
删除元素: erase(p),erase(b,e),clear(),pop_back(),pop_front()则只适用于 list和 deque
注意: pop_front和 pop_back函数的返回值并不是删除的元素值,而是 void。要获取删除的元素值,则必须在删除元素之前调用 front或 back函数
赋值操作: c1=c2,c1.swap(c2),c.assign(b,e),c.assign(n,t)
assign操作:首先删除容器中所有的元素,然后将其参数所指定的新元素插入到该容器中
带有一对迭代器参数的 assign操作允许我们将一个容器的元素赋给另一个不同类型的容器
注意:如果在不同(或相同)类型的容器内,元素类型不相同但是想到兼容,则其赋值运算必须使用 assign函数
swap操作:不且删除或插入任何元素,而且保证在常量时间内实现交换。由于容器内没有移动任何元素,因此迭代器不会失效
9.4
vector容器的元素:以连续的方式存放,每一个元素都紧挨着前一个元素存储。这样添加新元素时必须重新分配存储空间,复制,再撤销旧的存储空间。因此,一般 vector的实现中,实际分配的空间要比当前所需的空间多一些,这样添加新元素时就无需时刻都要重新分配存储空间
list容器的元素:以链表的形式存放,非连续的存储空间
vector的 capacity()函数:容器在必须分配新存储空间之前可以存储的元素总数,而 size()指容器当前拥有的元素个数
reserve()函数:告诉 vector容器应该预留多少个元素的存储空间
vector的每种实现都可自由地选择自己的内存分配策略。然而,它们都必须提供 reserve和 capacity函数,而且必须是到必要时才分配新的内存空间。
9.6
string类型:视为字符容器,提供了与 vector容器相同的操作,所不同的是, string类型不能使用栈方式的操作,这包括 front,back和 pop_front,pop_back
string字符也是连续存储的
将数组作为参数传递时,数组名将自动转换为指向其第一个元素的指针
只适用于 string类型的操作: s.substr(pos,n), s.substr(pos), s.substr(), a.append(args), s.replace(pos,len,args), s.replace(b,e,args)
string类型的查找操作: s.find(args), s.rfind(args), s.find_first_of(args), s.find_last_of(args), s.find_first_not_of(args), s.find_last_not_of(args),返回查找到的位置,为 string:size_type类型,若没找到则返回 string::npos值
注意:查找时字母匹配大小写
string对象的比较:关系操作符 ==, !=, <, <=, >, >=, 还有 compart(args)函数,这类似于 C中的 strcmp函数
9.7
C++中的适配器:容器适配器、迭代器适配器、函数适配器
顺序容器适配器: stack, queue, priority_queue
适配器的初始化:默认构造函数、带一个容器参数的构造函数
默认的 stack和 queue都基于 deque容器实现,而 priority_queue则在 vector容器上实现。可以指定一个顺序容器作为第二个模板参数来覆盖其关联的基础容器。
stack< string,vector<string> > str_stk;
stack:在 <stack>中,可以建立在 vector,list或 deque容器之上
queue:要求其关联的基础容器必须提供 push_front运算,因此只能建立在 list, deque上
priority_queue:要求提供随机访问,因此不能建立在 list上
栈 stack中操作: empty(),size(),pop(),top(),push(item)
队列 queue和优先级队列 priority_queue:在< queue>中, empty(),size(),pop(),push(),front()和 back()则只适用于 queue, top()只适用于优先级队列
总结:
顺序容器 (vector,list,deque)的操作,顺序容器适配器 (stack,queue,priority_queue)的操作,容器中元素类型的约束
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: