c++Primer笔记

打开一个仅用于输出文件:ofstream outfile("copy.out",ios_base::out);//文件名,打开模式
ios_base::out 输出模式  ios_base::app 附加模式,输出模式打开已经存在的文件,则文件中的数

据将被丢弃,如果附加模式打开,新数据将添加在文件尾部,两种模式中,如果文件不存在,程序会创建

一个新文件.
打开一个作为输入的文件:ifstream inFile("filename")
   outFile.puc(ch);     inFile.get(ch)
我们既可以用C风格字符数组的形式读入字符串,也可以以string类类型的形式读入字符串.string的

好处是与字符串相关的内存可被自动管理.

while( cin>> ival) 从标准输入读入一个序列,知道cin为false为止,有两种情况会使一个istream

对象被计算为false:读到文件结束(在这种情况下,我们已经正确的读完文件中所有的值)或遇到一个

无效的值,比如3.1515926
缺省情况下,所有空白符会丢掉,如果希望读入空白符,或许是为了保留原始的输入格式,或者是为了

处理空白符,一种方法是使用istream的get()(ostream对应put);

缺省情况下,false文字值被输入为0,而true被输出为1

max( int val1, int val2) { cout<<(val1 >val2)? val1:val2; }
则max(10,20)则输出0,因为<<的优先级高于?的有限级
正确的应为:{ cout<<((val1 >val2)? val1:val2); }

在程序中使用iostream库,必须包含相关的头文件,如#include
输入输出操作是有istream(输入流)和ostream(输出流)类提供的,iostream是同时从istream和

ostream派生,允许双向输入/输出.为了方便,这个库定义了三个标准流对象:

(用户终端的读写操作)
cin:代表标准输入的istrem对象,使我们能够从用户终端读入数据
cout:代表标准输出的ostream对象,cout能使我们能够向用户终端写数据.
cerr.

对文件的读写操作:include
ifstream:从istream派生,把一个文件绑到程序上用来输入.
ofstream:从ostream派生,把一个文件绑到程序上用来输出.
fstream:从iostream派生,把一个文件绑到程序上用来输入和输出.
由于fstream头文件中也包含了iostream头文件,所以我们不需要同时包含这两个文件

/*FILE *fp,*outf;
int ch;
while((ch=fgetc(fp))!=EOF)
{
cal[ch]++;
in_num++;
}
fclose(fp);*/
=====================================================================================
   重载的操作符在类体中被声明,声明方式同普通函数一样,只不过他的名字包含关键字operator,

以及紧随其后的一个预定义操作符.

类的初始化有一种可替换的方式:成员初始化表,是由逗号分开的成员名极其初值的列表.成员初始化

表只能在构造函数定义中被制定,而不是在其声明中,该初始化表被放在参数表和构造函数体之间,由

冒号开始.

如果一个类声明了一个包含多个参数的构造函数,但没有声明缺省构造函数,则每个类对象的定义都

必须提供所需的实参.在实践中,如果定义了其他的构造函数,则也有必要提供一个缺省构造函数.

嵌套类:除非外围类被声明为嵌套类的友元,否则他没有权利访问嵌套类的私有成员.嵌套类也没有任

何特权访问外围类的私有成员,如果要授权,也必须把它声明为嵌套类的友元.

位域(bit-field):它可以被声明存放特定数目的位,位域必须是有序数据类型,位于标识符后面跟一

个冒号,然后一个敞亮表达式制定位数.如:
typedef unsigned int Bit;
class File
{
public:
  Bit a:7;
  Bit b:8;
  Bit c:6;
}

联合是一种特殊的类,一个联合中的数据成员在内存中的存储是互相重叠的,每个数据成员都在相同

的内存地址开始.分配给联合的存储区数量是"要包含它最大的数据成员"所需的内存数.

静态成员函数访问静态数据成员

s2为某类对象的指针 表达式 s2->height() 可以写成 (*s2).height() 结果完全相同   

    一个友员或许是一个名字空间函数,另一个前面定义的类的一个成员函数,也可能是一个完整的

类.在使一个类成为友员时,友员类的所有成员函数都被给予访问"授权友谊类的非公有成员"的权利.

信息隐藏:
公有成员(public):在程序的任何地方都可以被访问.
私有成员(private):只能被成员函数和类的[友元]访问
保护成员(protected):对派生类就像public一样,对其他程序则表现的像private.
默认的是private

除了静态数据成员外,数据成员不能在类体中被显式的初始化,如:class firts{ int meni=0;}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
c++语言要求绑定在const vector上的iterator也必须是const iterator
const vector vec; vector::const_iterator iter=vec.begin();

抛出异常:在C++中,异常常常用类class来实现. 如class popOnEmpty();
throw popOnEmpty();//抛出异常是一个构造函数表达式
try 块必须包围能够抛出异常的语句,try块以关键字try开始,后面是花括号括起来的语句序列,在

try块之后是一组处理代码,被称为catch语句.
try{ ... } catch(pushOnFull){ ... }
           catch(popOnEmpty){ ... }
如果catch子句不包含返回语句,catch子句完成它的工作后,程序的执行将在CATCH子句列表的最后子

句之后继续进行.C++的异常处理机制是不可恢复的,一旦异常被处理,程序的执行就不能够在异常被

抛出的地方继续.
-------------------------------------------------------------------------
422 int min(int (&r_array)[size]) { ... }
300
在C++中,数组永远不会按值传递,它是传递第一个元素的指针.数组的长度不是参数类型的一部分,函

数不知道传递给它的数组的实际长度,一种常见的机制是提供一个含有数组长度的额外参数.

另外一种机制是将参数声明为[数组的引用],当参数为一个数组类型的引用时,数组长度成为参数和

实参类型的一部分,编译器检查数组实参的长度与在函数参数类型中指定的长度是否匹配.
例如:void putValue( int (&arr)[10] )

参数可以是多维数组,这样的参数必须指明第一维以外的所有维的长度
例如:void putvalue( int matrix[][10],int rowsize)
int (*matrix)[10];//一个二维数组,每行由10个列元素构成
int *matrix[10]   //一个含有10个指向int的指针的数组
[]的优先级高于*
-------------------------------------------------------------------------
如果两个函数的返回类型和参数表精确匹配,则第二个生命为第一个的重复声明.
函数的返回类型不足以区分两个重载函数.

空类大小为1;

标准C++库中的所有组建都是在一个被称为std的名字空间中声明和定义的.在标准头文件(如

)中声明的函数,对象和类模板,都被声明在名字空间std中.名字空间std的成

员不能不加限定修饰访问,最简单的解决方案是在#include指示符后面加上using指示符如下:
using namespace std;

常量对象的动态分配:const int *pci=new const int(1024);//必须初始化,前后必须都有const

C风格字符串 char *str="123456789"长度为9,实际占用空间为10,都以空字符结尾,所以要复制的时

候要多申请一个字节的空间,sizeof=10 ;strlen=9;
char *str2= new char[strlen(str)+1];否则会发生内存错误
strcpy(str2,str);

申请动态二维数组:
int **pi=new int*[m];
for(int i=0; ipi[i]=new int[n];

for(i=0; idelete [] pi[i];
delete [] pi;

三个指针常见错误:
 1.应用delete表达式失败,使内存无法返回空闲存储区,称为内存泄漏.(memory leak)
 2.对同一内存应用了两次delete表达式.通常发生在两个指针指向同一个动态分配对象的时候.通过

某个指针释放对象,该对象的内存返回给空闲存储区,然后又被分配给某个别的对象,接着指向旧对象

的第二个指针被释放,新对象也就跟着消失了.
 3.delete后,指针没设置为0;

if(pi != 0) delete pi;  //没必要,如果指针操作数被设置为0,则C++会保证delete表达式不会调

用操作符delete(),所以没必要测试其是否为0.
空闲指针是程序错误的一个根源,很难被检测到,一个较好的方法是在指针指向的对象被释放后,将该

指针设置为0,这样可以清楚的表明该指针不再指向任何对象.
    delete表达式只能应用在指向的内存是用new表达式从[空闲存储区[分配的指针上, 将delete表

达式应用在指向空闲存储区以外的内存的指针上,会使程序运行期间出现未定义的行为.
如:int i=8; int *pi=&i;  delete pi;//不安全,pi指向i,是一个局部对象,运行会发生内存错误
    int *pi2=new int(9); delete pi2;//安全

动态分配的对象被分配在程序的[空闲存储区的内存池]中.空闲存储区的一个特点是,气宗分配的对

象没有名字,new表达式没有返回实际分配的对象,而是返回指向该对象的指针,对该对象的全部操作

都要通过这个指针间接完成.第二个特点是分配的内存是未初始化的,空闲存储区的内存包含随机的

位模式,它是程序运行前该内存上次使用留下的结果.
因为空闲存储区是有限的资源,所以当我们不再需要已分配的内存时,就应该马上将其返还给该空闲

存储区,这是很重要的.

在局部域中的变量声明中引入了局部对象,有三种局部对象:自动对象(automatic object),寄存器对

象(register object),局部静态对象(local static object)
    自动对象的存储分配发生在定义它的函数被调用时,分配给自动变量的存储区来自于[程序的运

行栈],它是函数的活动记录的一部分.未初始化的自动对象包含一个随机的位模式,是该存储区上次

被使用的结果,它的值是为指定的.函数结束时,它的活动记录被从运行栈中弹出,与该自动对象关联

的存储区被真正的释放.
    在函数中频繁被使用的自动变量可以用regester声明.如果可能的话,编译器会把该对象装载到

机器的寄存器中,如果不能够的话,则该对象仍位于内存中.
for( register int ix=0; ix   把局部对象声明为static,把对象在整个程序运行期间一直存在的局部对象,当一个局部变量的值

必须在多个函数调用之间保持有效时,我们不能使用普通的自动对象,自动对象的值在函数结束时被

丢弃,可以声明为static,静态局部变量对象被程序自动初始化为0; 
void fuc() { static int depth; }


extern为声明但不定义一个对象提供了一种方法,该方法承诺了该对象在其他地方被定义:或者在此

文本文件的其他地方,或者在程序的其它文本文件中,例如 extern int i;关键字extern也可以 在函

数声明中指定.

名字解析期间查找域的顺序由内向外,所以在外围域中声明被嵌套域中的同名声明所隐藏.

用来区分名字含义的一般上下文就是域(scope),C++支持三种形式的域:局部域(local scope),名字

空间域(namespace scope),类域(class scope).
名字解析是把表达式中的一个名字与某一个声明想关联的过程.

函数参数的类型不能是函数类型,函数类型的参数将被自动转换为该函数类型的指针.

int sort(string*, string*, int (*)(const string &, const string &));
等价与 typedef int (*PFI2S)(const string &, const string &);
       int sort(string*, string*, PFI2S);

        int(*testCases[10]) ();//函数指针数组
等价于: tepedef int(*PFV)();
        PFV testCases[10];

函数指针初始化和赋值: int lexicoCompare(const string &s1, const string &s2) { ... }
函数名lexicoCompare被解释成 int (*)(const string &, const string &)的指针,将取址操作符

作用在函数名上也能产生指向该函数类型的指针,因此lexicoCompare AND &lexicoCompare类型相同

,指向函数的指针可以如下初始化:
   int (*pfi)  (const string &, const string &) = lexicoCompare;
OR int (*pfi2) (const string &, const string &) = &lexicoCompare;
只有当复制操作符左边指针的参数表和返回类型与右边函数或指针的参数表和返回类型完全匹配时,

初始化和赋值才是正确的.
应用函数指针时,用 pf(ia,size) OR (*pf)(ia,size) 而不能用 *pf(ia,size);

函数指针:函数名不是其类型的一部分,函数的类型只由它的返回值和参数表决定.
int  *pf  (const string &, const string &); NO
int (*pf) (const string &, const string &); YES

实际上,命令行选项是main()实参
int mian(int argc, char *argv[]) { ... }
argc:命令行选项的个数,argv包含argc个C风格字符串,代表了由空格分割的命令选项.argv[0]总是

被设置为当前正被调用的命令,从索引1到argc-1表示被传递给命令的实际选项.

*************************************************************************
调用函数有一个严重的缺点:调用函数比直接计算要慢的多,不但必须拷贝实参,保存机器的寄存器,

程序还必须转向一个新位置.内联函数(inline)函数给出了一个解决方案.它将在程序中的每个调用

点上被"内联地"展开. 一个递归函数不能在调用点完全展开(虽然第一个调用可以),一个大的函数也

不太可能在调用点展开,一般的,inline机制用来优化小的,只有几行的,经常被调用的函数.

为了替换一个大型的参数表,程序员可以将参数声明为类(或结构体),数组或某一容器类型,这样的参

数可以用来包含一组参数值.类似的情况,一个函数只能返回一个值,如果程序要求返回多个值,那么

程序员可以将某些函数参数声明为引用,这样,函数可以直接修改实参,或者可以声明一个函数,它的

返回类型是一个可以包含一组返回值的类或某一种容器类型.

一个程序中各种函数通过两种机制进行通信,一种方法是使用全局对象,另一种方法是使用函数参数

表和返回值.

缺省情况下,函数的返回值是按值传递的.局部对象的生命期随函数的结束而结束,在函数结束后,该

引用变成未定义的内存的别名.在这种情况下,返回类型应该被声明为非引用类型,然后在局部对象的

生命周期结束之前拷贝局部变量.
函数返回一个左值,对返回值的任何修改都将改变被返回的实际对象

省略号参数:当我们无法列出传递给函数的所有实参的类型和数目,这时我们可以使用省略号(...)指

定函数参数表.省略号挂起类型检查机制,它的出现告知编译器,当函数被调用时,可以有0个或多个实

参,而实参的类型位置,两种形式:void foo(para_list,...)  void foo(...);
for example: int printf( const char* ...)

缺省实参:函数声明可以全部或部分参数制定缺省实参,在左边参数的任何缺省实参被提供之前,最右

边未初始化参数必须被提供缺省实参.这是由于函数调用的实参是按照位置来解析的.
         int ff(int a, int b, int c=0)
重新声明:int ff(int a, int b=0, int c)

指针,引用的区别:引用必须初始化为指向一个对象,一旦初始化了,它就不能再指向其它对象,而指针

可以指向一系列不同的对象也可以什么也不指向.引用参数的一个重要用法是,它允许我们有效的实

现操作符重载的同时,还能保证用法的直观性.
    因为指针可以指向一个对象或者没有任何对象,所以函数在确定指针实际指向一个有效的对象之

前不能安全的解引用(dereference)一个指针.所以在使用指针作为参数时,我们必须首先判断指针是

否为空 ptr == 0 OR ptr == NULL

如果要修改指针本身,而不是指针引用的对象,那么可以声明一个参数,该参数是一个指针引用
如:void ptrswap(int *&v1, int *&v2){}

函数要想操作实参,就用指针传递或者引用传递,不能用值传递

for循环内部定义的对象的可视性局限在for循环体内,外部访问非法,WHILE循环也一样

在if(condition)中condition中定义的对象,旨在与if相关的语句或语句块儿中可见.试图在if语句

后面访问会导致编译错误.

字符在进行算数运算是取其ASC码,如 'a'为97; 3+'a'=100

C++在运算前自动进行算数转换,以便在计算前转换成相同的类型,转换规则是小类型总是被提升为大

类型,以防精度损失.

&:按位与  &&:逻辑与;  >>移位操作必须有左值,否则会返回去,例如 a>>3;A右移了3位,输出A时还

是原值,要实现移动效果 A= A>>3;也可以实现整数位移,如 5<<8;//5左移8位

逗号表达式是一系列由逗号分开的表达式,这些表达式从左向右计算,结果是最右边表达式的值

系统为每个程序提供了一个在程序执行时可用的内存池.这个可用的内存池被称为程序的 空闲存储

区 或 堆.运行时刻的内存分配被称为动态内存分配.

SIZEOF()一个对象或者类型名的字节长度,应用在数组上时,返回整个数组的字节长度

数组标识符代表数组中第一个元素的地址,*IA相当于IA[0],*(IA+1)相当于IA[1]

字符串(常量)包含一个额外的终止空字符

非CONST变量不能被用来指定数组的维数

如果有必要,算术值和指针值也能隐式的转换成BOOL类型的值,0或空指针被转换成FALSE,所有的其它

值都被转换成TRUE;

引用主要被用作函数的形式参数,通常将类对象传递给一个参数.

const对象的地址只能赋值给const对象的指针,但是指向const对象的指针可以被赋以一个非const对

象的地址,而且该非const对象不能通过const指针改变.

INT *P=0; 空指针

字符串被存储在一个字符数组中,一般通过一个 CHAR* 类型的指针来操纵它

任何人如果事先不知道指针是否有值,都应该先行测试,然后才对指针进行操作

如果我们要做的仅仅是持有地址值(可能把一个地址同令一个地址比较),那么指针的实际类型就不重

要了.C++提供了一种特殊的指针来支持这种需求:空类型指针(VOID*),它可以被任何数据指针类型的

地址值赋值.不能操作空类型指针所指向的对象.

指针:为清楚起见,最好写成  int *x  而不是  int*  x;
int * x,y;X是指针,而Y则不是

右值:被读取的值 左值:位置值

字符文字前加L表示宽字符文字,如L'a',宽字符常量用来支持某些语言的字符集合,如汉语

整数文字常量可以被写成十进制,八进制,十六进制,但这不会改变整数值的位序列.
string类型支持通过下标操作符访问单个字符

判断字符串是否结束: *str++;不结束为TRUE,结束时为FALSE
WHILE( *STR++) COUT<<*STR;   最后STR指针指向该字符串的后一个地址,要正确使用需要返回!(参

考STRCPY)
指针为空,则str=0

20 023,0X14,在整形文字常量后加L,将其指定为LONG整形.加U将其指定为一个无符号数

迭代器是一个支持指针类型抽象的类对象

  一般来说,当两个或多个函数重复相同的代码时,就会将这部分代码抽取出来,形成独立的函数,以

便共享,以后,如果需要改变这些实现,则只需改变一次.

    函数调用比直接访问内存的开销要大的多;内联函数在他的调用点上被展开,类定义中被定义的

函数会被自动当作是内敛函数

int *pint=new int(12);//分配指针指向一个整形,赋初值为12  delete pint;
int *pia= new int[4]; //分配一个4个整数元素的数组        delete [] pia;

C++中,指针的主要作用是管理和操作动态分配的内存

防止一个头文件被多次包含:
#ifndef BOOKSTORE_H
#define BOOKSTORE_H

Bookstore.h内容

#endif

程序中用 #ifdef  #endif来判断一个预处理器变量是否已被定义
------------------------------------------------------------------
文件输入输出:#include
ofstream outfile("out_file")
ifstream infile("in_file")
infile>>a;
outfile<

数组之间不能直接复制 如 A=B,数组不知道自己的长度

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/adriano119/archive/2008/09/22/2963420.aspx

你可能感兴趣的:(c++Primer笔记)