c++ primer plus知识点总结

#include<iostream>

int main(){

using namespace std;//可以写在main外,为全局

//using std:cin;

//using std:cout;

//using std:endl;

int n;//声明变量

cout<<"how are you"<<endl;//输出how are you并换行

cin>>n;//输入

cout<<"how are you"<<n*2<<endl;//输出how are you和变量n*2的值 变换行

return 0;

}

/*

cout是一个类的对象

endl是换行,不加不换行

using是一个编译指令,std里面所有的名称都加载一遍,就可以使用了

也可以不用using namespace std;

直接

using std:cin;

using std:cout;

using std:endl;

using namespace std;声明cout,cin,endl

using namespace std在头文件iostream中,预处理

*/

x=sqrt(4);//sqrt(double x)开根号函数,返回double类型

double sqrt(double x);//这是一个数学函数

cmath头文件(老系统为math.h)无需声明,直接使用sqrt()

基本类型,复合类型(数组,字符串,指针,结构)

_开头定义变量,不会报错,但是有可能会调用复合类型比如_Complex

简单变量:

(0~255)8个bit,两个字节

整形:short(16)、int(>=short)、long(32)、long long(64)

#include<climits>//符号常量

可以调用INT_MAX、SHRT_MAX、LONG_MAX、LLONG_MAX等符号常量即int型的最大值如int n_int=INT_MAX;

sizeof(int)//返回int类型所占的字节数量//sizeof()判断类型所占内存大小

int n=5;//5为字面值常量

区别于c语言的另外的初始化方式

int a(5);//int a=5;

int a={5};//int a=5;

无符号类型

unsigned 本身是 unsigned int 的缩写

无符号类型表示的值更大

short(-32768~32767)

unsigned short(0~65535)

改变第一位符号位

无符号的最大值在SHRT_MAX等前面加个U,即为 USHRT_MAX等

进制

八进制,第一位为0开头

十六进制,以0x或0X开头,A~F为10~15

想要输出不同进制的数,需要在输出前声明dec、hex、oct

cout<<dec; //十进制

cout<<hex; //十六进制

cout<<oct; //八进制

hex位于名称空间std中

如果省略编译指令using,而使用作用解析符std::cout,std::endl,std::hex,std::oct,可将hex用作变量名,但不建议使用

cout<<

cin>>

流向不同

数值没有后缀,默认为int型

unsigned long --->ul

long ---> L

long long ---> LL/ll

unsigned long long --->ull/uLL/ULL

char类型

每个字符都有"数值编码"

0~256,一个字节就足够表示所有字符

A65,a97

字符串""

字符''

成员函数 cout对象

cout.put(字符)

输出一个字符

.成员运算符

以前cout不能打印不出来字符只能打印出字符的数值,当时需要cout.put()才能打印出

有些字符不能直接通过键盘输入

\a振铃字符

char a=\a;

cout<<a会发出振铃报警铃声

使用endl比\n更容易

'\032'得到相应的字符常量

\b退格键

char类型在默认情况下既不是有符号,也不是没有符号

unsigned char类型的表示范围通常为0~255

signed char类型的表示范围为-128~127

wcha_t 宽字符类型,可以表示扩宽字符集

wchar_t是一种整型类型,可以表示系统使用的最大扩展字符集

underlying类型 底层类型也是一种整型'

对底层类型的选择取决于实现,在一个系统中。可能是unsigned short,另一个系统中,则可能是int

cin和cout将输入和输出看作char(字节)流,因此不适于用来处理wchar_t类型

iostream最新版中wcin和wcout,可用于处理wchar_t流

加上前缀L,指示宽字符常量和宽字符串

wchar_t bob=L'p';

wcout<<L"tall"<<endl;

国际编程使用Unicode或ISO 10646

bool类型,true/false

预定义的字面值true/false表示真假

true/false可以赋值int类型,1/0

任何数字值或指针值都被隐形转换为bool值 ,非零转换为true,零转换为false

当多个地方需要使用同一个变量,可以用#define

const限定符

固定变量的值,防止它被修改

const int a;不允许在赋值了

const比#define更好,因为const明确指定了类型

浮点数

分为两部分来存储

一部分表示值,一部分用于对值进行放大或缩小

34.1245 0.3412545(基准值) 100(缩放因子)

E6 10^6 1000000

2.52e+8 +号代表小数点向右移

2.52e-8 -号代表小数点向左移

浮点类型

float,double,long double

<cfloat> <float.h>

整数部分:10

10.25

除数 被除数 余数

2 10 0

2 5 1

2 2 0

2 1 1

二进制为1010

小数部分:0.25

0.25*2=0.5-->0

0.5*2=1.0-->1

二进制为01

科学计数法的方式为 1.01001*2^3

单精度有效位32位

第一位为符号位,0为正,1为负

八个比特位为指数位2^8=256

0~127表示正指数的二进制,127~255表示负指数的二进制

2^3为127+3的二进制数表示10000010

符号位 指数位 尾数(小数点后面的)

0 10000010 01001000...0

默认状态下通常cout会将小数点最后的0删掉

cout_setf(ios_base::fixed,ios_base::floatfield);覆盖掉默认模式

输出时小数位后面所有的0被保留

有效位只显示6位

float

系统确保7位是精确的,至少有6位

double至少有13位有效

#include<iostream>

int main(){

using namespace std;

float hats;

cout.setf(ios_base::fixed,ios_base::floatfield);//定点模式

cin>>hats;

cout<<hats;

//顶点模式,小数点6位后面全部显现

return 0;

}
//浮点型默认为double型

浮点型转整形,结果是不确定的

缩窄(narrowing)

int x=66;

char c4={x};//初始化列表

强制类型转换符

static_cast<long>(thorn);//将thorn转为long型

auto n=100;//auto将变量设置为与初始值相

auto x=1.5;

std::vector<double>across;

std::vector<double>::iterator pv=across.begin();

转换为 auto pv=across.begin();更简单

复合类型

数组

sizeof(int)//int的空间大小

只有在定义时才能使用成员初始化列表

short thing[]={1,2,3};//自动记录元素个数;

int num=sizeof things/sizeof(int);//具体的元素个数

int a[3] {1,2,3};//=可省略

int a[3]={};//所有的元素都设置为0

取值范围大的变成一个取值范围小的,缩窄

字符串

'\0'结尾

char a[]="";//根据字符串长度来定义a的长度

'\0'后面都为'\0'

双引号实际上表述的是一个地址

拼接字符串常量安排

空格、制表符、换行符分隔的两个字符串都将自动拼接成一个

cout<<"I love you" "are you ok";

char a[10];

cin>>a;//给字符串赋值

strlen(a);//有多少个实际字符,不包括'/0'

cout里也能用'\n'换行

cin把空白符(空格,制表符,换行符)作为就结束标志

字符串以/0作为结束标志

cout以空字符'/0'作为结束标志

面向行的读入:getline(),get()

istream类中的getline()成员函数

cin.getline(存储输入行的数组的名称,读入字符的个数)

字符串一定要有'/0'

通过换行符确定行尾,会丢弃回车换行符,存储字符串时用空字符('/0')替换换行符

面向行的读入:get()

get()不会丢弃回车换行符

cin.get(name,13)去捕获内容的时候,回车换行符会被留在缓存区里面

get(name,13)读取空行的时候,会设置一个失效位,cin就不能用了

重载函数get()可以读取换行符,看可以用get()来去掉这个失效位

cin.get(name,13);

cin.get();//读取下一个字符

cin.get(name,13)返回一个cin对象,该对象随后将被用来调用get()函数

cin.getline(name,13).getline(dessert,13);//链式编程,getline可以这样写,get不行,因为会产生失效位

get可以知道是读取了整行还是数组填满

cin.clear();//可以将失效位复位

如果输入行包含的字符出比指定的多,getline和get会把余下的字符留在输入队列中

cin读取年份,即将回车键生成的换行符留在了队列中,cin.getline()看到换行符后,将认为是一个空行,并将空字符串赋给address数组,解决:读取地址之前先读取并丢弃换行符

没有参数的get()和使用接受一个char参数的get()

(cin>>year).get();将换行符读取读取丢弃

(cin>>year).get(ch);可以将换行符读到ch中

string是保存在std里的

using namespace std;

或者std::string;

char ch[20]="junar";

string str="aa";

可以str[]来提取字符串中的字符

string对象可以字符的给予空间

也可以用初始化列表赋值{}

不能把数组赋值给另一个数组,因为数组是地址

可以把string对象赋给另一个对象

+拼接字符串

cstring头文件中

strcpy(a1,a2)可以将字符串复制到另一个字符数组中

a1需要比a2大,或是把报警系统关了

strcat() 将字符串添加到字符数组末尾

size()是string类的成员函数 str1.size(),计算字符串的长度

c风格字符串成员函数:strlen(char1)

对象不能作为函数参数

string类的I/O

只有带/0的才是c风格的字符串,不然只是char数组

char charr[20];

string str;

cin.getline(charr,20);大于19个字符,会设置一个失效位

getline(cin,str); 将cin输入流里的内容放到str里

cin>>x是istream类的一个成员函数

istream没有处理string对象的方法

cin>>str;处理string对象的代码使用string类的一个友元函数

结构简介

结构是一种复合类型

struct inflatable{

...

};

c语言:struct inflatable goose

c++ :inflatable goose

两种风格都好

inflatable guest={

"Glorious Gloria",

1.88,

29.99

};// =可有可无

结构体可以赋值给另一个结构体

struct perks{

int x;

}a,b;

结构定义和变量声明可以写在一起

结构数组

inflatable gift[100];

cin>>gifts[0].volume;

可以初始化列表

inflatable guests[2]={

{"ada",0.2,12,44}.//guess[0]

{"sdfaf",0,3,123,33}//guess[1]

};

共用体union

可以存储不同类型,但同时存储其中的一种类型

用哪个,表现哪个类型

结构体内可以嵌套匿名共用体

匿名共用体没有名称,变量的地址相同

枚举enum

enum spectrum{red,orange.yellow,green,blue};//0~3

可以显式的指定整数值来覆盖默认值

spectrum band;

可以将枚举量赋(如yellow)给枚举变量(band)

枚举变量可以进行计算++band

枚举量可以变为整型,整型不能变为枚举量,除非强制类型转换,且空间不能超过最大枚举量

band=spectrum(3);

band=spectrum(40003);//超出范围

enum bits{one=1,two=2,four=4};

enum bigstep{first,second=100,third}

可以创建多个值相同的枚举量

enum{zero,full=0,one,numero_uno=1};

最大值:大于最大枚举量的最小2次幂

如果枚举量为-6,下限的为-8+1为-7

OOP在运行阶段确定数组的长度

int* p指针

指向int的指针,地址不是int类型

p地址

*p地址所指向的值。解引用

地址是指定的量,值是派生量

通过解引用修改,该地址上的所有变量值也会修改

把地址强制类型转化,才可以赋值给指针

int * p;

p=(int *)0xB800000;

C语言中malloc()来分配内存

c++中,new分配内存,并返回该内存块的首地址,程序员并赋给一个指针

int *p= new int;

指向什么类型,new开辟什么类型

sizeof 打不打括号都一样

地址根据计算机64位,统一8个字节

new从堆heap或自由存储区free shore的内存区域分配内存

new 范返回值为0的指针为空指针null pointer

delete释放内存

int *p=new int;

delete p;

释放的是p指向的内存,指针p不会被删除掉

new和delete配对使用,否则发生内存泄漏memory leak

内存不要尝试重复释放,结果是不确定的

空指针使用delete是安全的

new来创建动态数组

在编译时给数组分配内存称为静态联编static binding

运行时选择数组的长度,动态联编,运行时创建的数组为动态数组dynamic array

int *psome=new int [10];//开辟

psome指向了首地址

delete [] psome;//释放

new带方括号,delete也带方括号,不带,都不带

psome指向动态数组第一个元素

psome可以当作数组名使用,psome[0],psome[1],psome[2]

psom=psome+1//psome[0]->psome[1],将首地址改为了下一个元素的地址,减1加1,首地址向左右移动

普通数组不能赋值,更改首地址,也可以加1减1,指向的值移动

stack[1]//c++编译器会看作*(stack+1)

c++不会将数组名作为地址来使用,sizeof(数组名),计算整个数组的地址大小

short psome[10];

psome=psome[0]//第一个元素的地址

&psome//数组名取地址是整个数组的地址

psome+1//加两个字节

&psome+1//加20个字节

short (*pas)[10]=&psome;//pas指向一个数组,且这个数组有10个元素

short* pas[10]//有一系列指向short类型的指针组成的数组

short (*pas)[10]//一个指针指向的数组

c风格字符串有\0

char flower[10]="rose";

字符串也是个地址cout<<"askdakl"<<endl;//""中也有隐式的\0

const char* bird="wren";//bird指向第一个字符的地址,w

字符串常量不能修改,不能对指向字符串常量的地址上修改字符串,可以修改指针,不能修改指针指向的值

cout只有在char类型,字符串,首地址才打印的是地址指向的值

(int*)animal//对地址int*类型转换,就不会打印字符串,而是打印地址

char *ps;

ps=new char[strlen(animal)+1]//strlen实际长度,1为\0

strcpy(ps,animal);//将animal里面的所有内容赋值到ps所指向的内存空间里

#pragma waring(disable:4996)

忽视警报

字符串常量是只读的,不能用来strcpy

strncpy(目的,源,长度)//指定cpy的长度

strncpy()结束后,给目的数组补上'\0'

string类型自动调节空间大小

new创建动态结构

inflatable * ps=new inflatable;

该结构没有名称,只有一个指向它的指针

-> 表示指向,访问成员、

(*ps).name

ps->name

先定义结构体inflatable,然后再inflatable *ps=new inflatable;

cin.get(ps->name,20);//读取一行,保留换行符

cin>>(*ps).volume;

delete ps;//delete与new配对

getname(),返回指向输入字符串的指针,将输入读入到一个大型的临时数组,用new []创建一个内存块并返回指针

char* getname(void);//声明getname函数

int main(){

char* name;

name=getname();

cout<<name<<" at "<<(int*)name<<"\n"

delete[] name;//delete掉动态数组

}

char* getname(){

char temp[80];//静态数组

cin>>temp;

char* pn=new char[strlen(temp)+1];//动态数组

strcpy(pn,temp);//将静态数组中的内容cpy到动态数组中

return pn;//返回那一块动态数组的指针

}

自动存储,静态存储,动态存储

自动变量,即局部变量,存储在栈中,先进后出被释放

静态存储,全局

动态存储,内存池内,new,delete,程序员控制,一个函数开辟,另一个函数释放,自由存储区并不连续。

结构体类型数组名->year=2003;

(数组名+1)->year=2004;

const years_ends *arp[3]={&sro1,&sro2.&sro3}

指向结构体的指针的数组,且值不可修改

const year_ends **ppa=arp; //指向结构体指针的指针

auto ppb=arp; //自动赋予变量类型

数组的代替品

模板类vector和array是数组的替代品

vector是一种动态数组,是new创建动态数组的替代品,new和delete自动完成

vector包含再std中,std::vector

using编译指令声明

vector<int> vi;

自动设置长度,末尾,中间插入数据

vector<typeName> vt(n_elem);

存储n_elem个类型为typeName的元素

array是长度固定的,使用栈(静态内存分配)

array<int,5> ad = {1,2,21,2.3,3.2,4.3};

array<type,n_elem>arr;

vector和array可用初始化列表

vector对象可以使用数组的方式对元素进行操作,a[0],a[1],a[2]

vector对象可以赋值给相同类型的vector对象

可以给未定义的位置进行越界赋值,中间的空白区域会被随机赋值

成员函数at()

a2.at(1)=2.3;//at()若越界会报错

cout<<setf(ios_base::boolalpha);判断表达式强制转化为bool类型

表达式加;可以转化为语句、

for()中声明的变量,不能在for外面使用

std::cout<<sda<<std::endl;

std::cout;

std::cin;

std::endl;

size()//计算string字符串长度的函数

自增,自减,顺序点sequence point,以分号为分隔

前缀格式效率更高

递增运算符可以用于指针

*++pt//pt=pt+1

++*pt//*pt=*pt+1

组合赋值运算符

i+=2;

局部可以看到外部,外部无法看到局部

局部的变量会隐藏全局的变量

逗号运算符,++j , --j 将两个表达式变成一个表达式

for(int j=0,i=5;j<i;--i,++j)

逗号运算符算是一个顺序点

cats=(12,88)括号的优先级最高,逗号表达式先看后面的值

word=="mate"//比较两个地址是否相同

strcmp()接受字符串地址作为参数

string类字符串,可以用关系运算符进行比较

编写延迟循环

clock()返回的单位不一定是秒

头文件ctime

CLOCKS_PER_SEC该常量等于每秒钟包含的系统时间单位数

系统时间除以这个值,可以得到秒数

colck_t作为clock返回类型的别名,编译器会将其转换为适合系统的其他类型

include<iostream>

include<ctime>

int main(){

using namespace std;

float secs;

cin>>secs;

clock_t delay=secs*CLOCKS_PER_SEC;//延迟的时间

clock_t start =clock();//当前系统时间

while(clock()-start<delay);//时间达到延迟时间为止

//依此来使系统延迟时间

return 0;

}

类型别名

typedef 类型名 别名

也可以使用#define声明别名

typedef更不容易出错

#define FLOAT_POINTER float *

FLOAT_POINTER pa,pb;

系统会将其转化为float * pa,pb;//pa使float *类型,pb则使float类型,#define取别名并不安全

基于范围的for循环

price[5]={1,2.3,4.5};

for(double x:price){

cout<<x<<endl;

}

for(int x:{1,2,3,4,5})

cin在读取时,空格会被忽略

char ch;

cin.get(ch)可以读取空格

cin.get(name,ArSize).get();

相当于

cin.get(name,ArSize);

cin.get();

检测文件尾(EOF)

重定向

eofbit和failbit都设置为1

eof()来查看eofbit是否被设置

如果监测到EOF,cin.eof()将返回true,否则false

如果eofbit或failbit被设置为1,fail()返回true

cin.get(ch);

while(cin.fail()==false){

cout<<ch;

++count;

cin.get(ch);

}

windows系统ctrl+z作为文件尾

ctrl+z一定要是在行首,才能作为文件尾

EOF结束输入

cin.get(ch)需要变为true和false时就会变为true和false

cin.get(ch);

while(cin)//直接捕获

while(!eof())

while(!fail())

EOF被定义为值-1

cout<<cin.get()<<endl;//输出97即第一个字符a

cin.get读取字符时,返回值是字符对应的ASCII码的十进制数,就是int

若成功读取字符,返回的都是正数,EOF是-1,所以EOF表示结束

cout.put(char(ch));//输出一个字符

cin.get(ch),字符true,结尾false

ch=cin.get(),字符int类型的字符编码,结尾EOF

while(ch=cin.get()!=EOF)

二维数组,初始化列表

int maxtemps[2][2]={

{1,2},

{2,3}

};

const int Cities=5;

const char* cities[Cities]={

"cajkhfjl".

"afjahfl",

"dafjkla",

"dfankf",

"dafaf"

};

//空间消耗过大

const char cities[Cities][25]={

"cajkhfjl".

"afjahfl",

"dafjkla",

"dfankf",

"dafaf"

};

const string cities[Cities]={

"cajkhfjl".

"afjahfl",

"dafjkla",

"dfankf",

"dafaf"

};//string类是自动修改

定义is_int(double x)函数判断是否位于int类型的范围内

x<=INT_MAX&&x>=INT_MIN

int(num)//强制类型转换

字符函数库cctype

isalpha(ch)如果是一个字符,则返回true

isspace(ch)是空格

i sdigit(ch)是数字

ispunct(ch)是标点符号

三目运算符

?:

cin输入的值与类型不匹配。n的值保持不变,不匹配的输入被留在输入队列中,cin对象中的一个错误标记被设置;

对cin方法的调用将放回false

clear()重置错误输入标记,也重置文件尾

输入错误和EOF都将导致cin返回false

简单文件输入/输出

文本I/O和文本文件

输入的是一系列的字节,解释为字符编码,输入一开始字符数据------文本数据

cin读到空白字符会终止

类型匹配,会设置失效位

写入到文本文件中

cout<<fixed;//设置定点模式

cout,precision(2);//设置精度

cout.setf(ios_base::showpoint)//显示小数点

文件输出

头文件fstream

输出ofstream

ofstream outFile;//必须自己创建一个对象

outFile.open("文件");//如果没有这个文件,系统会自动创建这个文件

写入文本文件

outFile<<fixed;

outFile<<precision(2);

outFile.setf(ios_base::showpoint);

outFile<<"afdaf"<<endl;//流入文件中

open会截断打开的文件,并且丢弃文件中原来的内容,输入新的内容

outFile.close();//关闭该文件

读取文本文件

ifstream

char filename[SIZE];

ifstream inFile;

cin.getline(filemame,SIZE);//数组存储文件名

inFile.open(filename);

if(!inFile.is_open())// 没有成功打开

{

cout<<"Could not open the file"<<filename<<endl;

exit(EXIT_FAILURE);//退出整个程序

}

//while(inFile>>value)//若读取成功,返回true,否则返回false

inFile>>value;//从文件中读取内容

while(inFile.good())//成功读取,inFile.good()返回true

{

//遇到空格,读取结束,光标移动到此处

}

if(inFIle.eof())//是否到文件尾

{

}else if(inFIle.fail()){//数据不匹配,导致中断

}else{

}

声明函数中,参数可以只写类型

如果参数类型不匹配,会自动转换为正确的类型

数组名作为参数传给函数

int num_arr(int* arr,int n)//数组。数组长度

arr实际上是一个指针,数组不能赋给数组

指针加const,就不会修改内容

cin>>temp;

if(!cin){//输入错误

cin.clear();

while(cin.get()!='\n')

continue;

cout<< "Bad input;input process terminated.\n"

break;

}

int sum=sum_arr(cookies,cookies+ArSize)//俩个指针作为参数

int sum_arr(const int* begin,const int* end)

{

const int* pt;

int total=0;

for(pt=begin;pt!=end;pt++)

total=total+ *pt;

return total;

}

int * const pt;//pt不能变,但pt所指向的值可以修改

字符串的函数原型是char* 类型

c风格字符串\0结尾

char mmm[15]="afhjka";

const char* wail="aijdiaj";//必须加const,因为字符串常量是只读的

char* buildstr(char c.int n){

char* pstr=new char[n+1];//第n+1个元素存的是\0

pstr[n]='\0';

while(n-- > 0)

pstr[n]=c;

return pstr;

}

结构体对象也可以用初始化列表

结构体可以按值传递,也可以按地址传递

按引用传递

string list[SIZE]

for(int i=0;i<SIZE;i++){

getline(cin,list[i]);//getline是一个函数,cin读取一行,存储到list[i]中

}

std::array<std::string,4>Snames={"Spring","Summer","Fall"."winter"}//有限长度的数组

若是地址传递array对象,(*p)[2]//需要先解引用在标明第几个元素

因为array不是真实的数组,p不能表示第一个元素,需要解引用后,在指明元素下标

包含多个递归的递归

函数也有地址。存储机器语言代码的内存的开始地址

estimate()

获取函数的地址

think(),think就是该函数的地址,函数作为参数进行传递,传递函数名,区分传递的是函数的地址还是函数的返回值

think作为参数

声明一个函数指针

指向函数的指针,必须指定指针指向的函数类型

使用函数指针来调用函数

double pam(int);

double (*pt)(int);//如果*pt是函数,pt就是函数指针

estimate(code,betsy); //函数作为参数

doule betsy(int lns){//作为参数的函数

return lns;

}

void estimate(int lines,double (*pf)(int))//函数指针作为参数,并使用该函数。

{

std:: cout<<(*pf)(lines)<<"hours\n";

}

const double* f1(const double* ar,int n){

return ar;//ar=ar+0=&ar[0]

}

const double* f2(const double ar[],int n){

return ar+1;//ar+1=&ar[1]

}

const double* (*p1)(const double*,int)=f1;//函数指针赋值

auto p2=f2;//自动获取函数指针类型

const double* (*p3[3])(const double*,int)={f1,f2.f3};//函数指针数组

p3[3]表示数组

*p3[3]表示指针数组

const double* *p3[3]表示类型为const double*的指针数组

p[1]存的的是函数地址

p=&p[0]是这个数组的首地址

函数的类型为double*

cout<<p[1](av, 3);//输出函数的返回值

p1(av,3)和(*(p1))(av,3),*p1(av,3)和*(*p1) (av,3)是等价的,但只限于函数指针

const double* (*(*pc)[3])(const double*,int)=&pa;

//*pc表示一个指针

//(*pc)[3]表示指向一个数组

//*(*pc)[3]表示是指针数组里的函数指针所指向的函数

//const double* 表示函数的类型

(*pc)[0](av,3)等价于(*((*pc)[0]))

typedef const double *(*p_fun)(const double *,int);//将p_fun声明为函数指针类型的别名

p_fun p1=f1;//将函数指针f1赋给p1

p_fun pa[3]={f1,f2,f3};//将数组f1,f2,f3初始化列表赋值给类型为p_fun的数组

p_fun (*pd)[3]=&pa;//pd=&pa;pa为数组首地址

内联函数比常规函数稍快,不需要跳转

内联函数用内联代码替换函数调用

声明和定义时加上关键字unliine

内联函数不能递归

inline double square(double x);

inline double square(double x){

return x*x;

}

#define SQUARE(X) X*X;

a=SQUARE(6.0) a=5.0*5.0;

b=SQUARE(4.5+7.5) b=4.5+7.5*4.5+7.5

宏不能按值传递

引用变量

int rates;

int & rodents = rats;//必须在声明引用变量时进行初始化

&不是地址运算符,而是类型标识符的一部分

rodents作为rats变量的别名

两个变量的地址和值都相同

引用作为参数,作为实参的别名,用的是同一个内存空间

引用变量作为参数

void swaper(int& a,int& b){

int temp;

temp=a;

a=b;

b=temp;

}

const double& ra;//ra不能修改

double cube(double a){//参数可以是常量

a *= a*a;

return a;

}

字符串常量可以取地址,字符常量不能取地址

const int& b=10;//加const赋值才能为右值

const int& b//作为参数,可以是右值

const string& b="abc";

int& d=a;//左值引用

int&& d='a'+2;//右值引用

结构的引用作为参数

free_throw& ft;

display(accumulate(team,one));//accumulate的返回值是free_throws& ,display的参数类型为const free_throws&

accumulate(accumulate(team,three),four);

void distplay(const free_throws& ft){

using std::cout;

}

free_throws& accumulate(free_throws& target,const free_throws& source){

return targat;

}

accumulate(dup,five)=four;

赋值语句,左边的子表达式必须标识一个可修改的内存块

string input;

getline(cin,input)//cin捕获到input里

引用类作为参数string& s1

ostream是基类,ofstream是派生类

派生类继承基类的方法

基类对象可以作为参数,派生类对象可以作为参数

oftream fout;

const char* fn="data,txt";

fout.open(fn);

if(!fout.is_open()){

cout<<Cant open:"<<fn<<"Bye.\n";

exit(EXIT_FAILURE);

}

double objective;

double eps[LIMIT];

file_it(cout,objective,eps,LIMIT);

void file_it(ostream& os,double fo,const double* fe,int n)

{

os<<"dafd";

}

参数默认值

若第一个赋了默认值,后面的也必须赋

int harpo(int n,int m=4,k=5)

harpo(2);//2,4,5

harpo(2,2);//2,2,5

harpo(4,5,6);//4,5,6

函数重载,同名函数

变量名相同,特征标不同

尝试使用强制类型转换

类型本身和类型引用视为同一个特征标

区分const和非const变量

double && r 右值引用

名称修饰

每个函数名进行加密

函数模板

使用泛型来定义函数

模板交换函数

template <typename AnyType>

void Swap(AnyType &a,AnyType &b)

{

AnyType temp;

temp=a;

a=b;

b-temp;

}

编译器根据类型生成有个具体的定义

显示具体化的原型和定义应以template<>打头 ,并通过名称指出类型

template <> void Swap<job>(job &,job &);

1.非模板函数

void Swap(job &.job &) //定义

2.模板函数

template <typename T>//模板

void Swap(T &,T &);

3.显示具体化模板函数

remplate<> void Swap<job>(job &,job &)//定义

优先级

非模板版本>显式具体化>模板生成的版本

实例化和具体化

Swap<int>(i,j)

//显式实例化//强制要求int

//隐式实例化,编译器自动 规定是int还是其他

template void Swap<int>(int,int);//显式实例化,加<>就是具体化

非模板>显示具体化>显示实例化> 实例

template<> void Swap(job&,job&);//显示具体化

template void Swap(job&,job&)//显示实例化

编译器有一个自主性,如果参数相同,且具体化在实例化前,则编译器自动放弃显示实例化

若是实例化在前,具体化在后,则编译器会报错,因为已经实例化,无法再具体化

隐式实例化,显式实例化,和显示具体化统称为具体化,使用具体类型的函数定义,而不是通用描述

模板都是在编译阶段完成的 具体化

完全匹配,常规函数优先于模板、

提升转换,(char和short自动转换为int,float自动转换为double)

标准转换,(int转换为char,long转换为double)

显式具体化和显示实例化同时出现的时候才会出现二义性

没有强调<>类型,选非模板

强调了,选模板函数

重载解析将寻找最匹配的函数

如果都是模板,则选择更具体的

int x;

decltype(x) y;//x是int类型,decltype就是int类型

long indeed(int);

decltype(indeed(3) ) m;//根据返回值

()并不会改变左值和左值性

auto h(int x,float y)->double//后置的返回类型

#表示预编译

#ifdef CON

#define CON

...

endif

#progma once可以替代上面三个#...

内联函数可以写在头文件里

翻译单元(translation unit)

自动存储持续性

自动变量,局部

静态存储持续性

static静态变量,全局

线程存储持续性

动态存储持续性

new自动变量,函数定义中定义的变量

作用域和链接

static 静态变量

默认情况下为0

定义声明,定义,开辟内存空间

double up;

引用声明,声明,不开辟内存空间

extern int blem;

使用外部变量,需要extern声明

自动变量放在栈中

静态变量放在静态区

::warning使用外部变量

在一块作用域内,谁在前用哪个

extern double warining;

double warning =0.8;

auto 自动变量

register 寄存器存储,变量是自动的

extern 引用声明,声明引用在其他地方定义的变量

thread_local 线程

volatile声明,没有对内存单元进行修改,值也可能发生变化

改善编译器的优化能力

查找两次,这个值缓存到寄存器中,若是不声明volatile,将进行这种优化

mutable

即使结构变量为const,某个成员也可以被修改

默认情况下全局变量的连接性为外部的,但const全局变量的链接性为内部的

由于外部定义的const数据的链接性为内部的,可以在所有文件中使用相同的声明

extern const int states =50;//const 为内部,加上extern又变成外部的

一个文件extern声明一个const变量,另一个文件extern声明,就可以使使用另一个文件的该变量

可在函数原型中使用关键字extern来指出函数是在另一个文件中定义的

static将函数的连接性设置为内部的,只能在一个文件中使用

在一个文件中定义函数,另一个文件可以调用,若另一个文件内部也定义一个该函数,则会冲突,可以使用static,使该函数称为内部链接的

重载函数生成不同的符号名称

spiff(int) _spiff_i

spiff(double,double) _spiff_d_d

使用c库函数中预编译的函数

c库文件中的符号名称为_spiff,c++查询约定是查找符号名称_spiff_i

可以用函数原型来指出要使用的约定

extern "c" void spiff(int);

extern void spoff(int);

extern "c++" void spaff(int);

new要初始化常规结构或数组,大括号的列表初始化

struct where{double x;double y;double x;};

where * one = new where{2.5,5.3,7.2};

int *ar=new int[4]{2,4,5,6};

也可用于单值常量

int *pin=new int {12};

int *pi=new int (6);

new失败返回空指针,引发异常std::bad_alloc

size_t a=10;

size_t,X64 8个字节,X86 4个字节

int * pi=new int;

int *pa=new int[40];

被转换为

int * pi=new(sizeof(int));

int *pa=new(40*sizeof(int));

delete pi;

转换为delete (pi);

定位(placement)new特性

使用定位运算符时,变量后面可以有方括号,也可以没有

char buffer1[50];//外部变量,静态变量在静态区里面

char buffer2[500];

int main(){

chaff *p1,*p2;

int *p3,*p4;

p1=new chaff;

p3=new int[20];

p2=new (buffer1) chaff; //在buffer1内开辟chaff类型大小的空间

p4=new (buffer2) int[20];

}

(*void)强制类型转换,求地址

定位new,buffer1的值会被覆盖掉

delete只能释放堆内存,不能释放静态内存

new (buffer+N*sizeof(double)) double[N];//从buffer+N*sizeof(double)开始开辟double[N]大小的内存

名称冲突

名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中

全局名称空间(global namespace)

不同名称空间中的名称不会冲突

namespace

访问给定名称空间中的名称

作用域解析运算符::,使用名称空间来限定该名称

Jack::fetch();

未被装饰的名称称为未被限定的名称(unqualified name)

包含名称空间的名称称为限定的名称(qualified name)

using声明

简化对名称空间中名称的使用

using声明将特定的名称添加到它所属的声明区域中

using声明将名称添加到局部声明区域中

在函数外面使用后using声明时,将把名称添加到全局名称空间中

using 使一个名称空间可用,而using编译指令使所i有的名称空间都可用using namespace

全局声明区域使用using编译指令,名称空间里的名称全局可用

namespace elements

{

namespace fire{

int flame;

...

}

float water;

}

element::fire::flame

也可以在名称空间里使用using编译指令和using声明

可以using该名称空间,使用该名称空间里的using的变量

可以给名称空间创建别名

namespace mvft=my_very_favorate_things;

未命名的名称空间

namespace

{

int ice;

}

不能显式地使用using编译指令或using声明

只能在当文件中使用

OOP面向对象

用户与数据交互:初始化,更新,显示

接口由公共方法组成

#ifndef STOCK00_H_

#define STOCK00_H_

#include<string>

class Stock

{

private:

std:: string company;

long shares;

double share_val;

double total_val;

void set_tot(){total_val=shares*share_val;}

public:

void acquire(const std::string& co,long n,double pr);

void buy(long num,double price);

void sell(long num,double price);

void update(double price);

void show();

}

#endif

公有成员函数是程序和对象地私有成员之间的桥梁

共有接口表示设计的抽象组件,称为封装,将实现的细节隐藏在私有部分中,也是一种封装、

类成员可以是数据也可以是函数

私有成员函数来处理不属于共有接口的实现细节

private是类对象的默认访问控制

结构体里面可以放函数

struct成员默认为public

定义成员函数,使用::来标识函数所属的类

类方法可以访问类的private属性

void Buffoon::update(double price);

将update()标识为成员函数

可以将另一个类的成员函数也命名为update()

void Buffoon::update();

定义位于类声明里的自动成为内联函数,使用iline限定符

函数声明在类中,函数定义在类外,用inline,也可以直接定义在类中

公有成员可以访问私有成员

可以在类声明中定义一个函数

单独提供函数定义,需要使用作用域解析运算符来指出成员函数属于哪个类

类对象不能直接初始化成员属性

Stock类构造函数Stock().构造对象,将值赋给它们地数据成员

默认提供,也可自己定义

Stock::Stock(const string &co,long n,double pr){

}

Sotck food= Stock("daf",12,1,22);//显式初始化

隐式初始化,默认的构造函数 Stock::Stock(){}

也可以用new开辟

Stock stock1;//需要自定义一个默认构造函数

系统会提供一个隐式的默认构造函数

若是定义了非默认构造函数,则不能在声明一个没有参数的类对象

对象的参数可以有默认值

只能有一个默认构造函数

Stock first=Stock();//显示的使用默认构造函数

Stock first{"daf"};//隐式的调用构造函数

析构函数

若Stock类对象没有new开辟,就不需要析构函数,只需要提供一个什么都没有的析构函数就好

Stock::~Stock(){

}

析构函数一定没有参数

类对象过期时自动调用析构函数

构造函数被用来创造对象,而对象不能调用构造函数

默认构造函数和非默认构造函数可以同时存在

Stock first=Stock();会调用析构函数,相当于创建一个临时的对象,然后赋值给first对象,临时对象生命周期结束,自动调用析构函数。

类之间可以互相赋值

有些编译器会延迟析构函数的调用

初始化效率更高

const放在函数的括号后面,保证函数不会修改调用对象

构造函数也可以重载

一个参数的构造函数可以使用赋值语句

Bozo tubby=32;

this指针

一个对象调用另一个对象作为参数

const Stock & topval(const Stock & s) const;//后面加const,不能调用topval对象里面的所有成员数据

this指针设置为调用成员函数的对象的地址

stock1.topval(stock2);//this设置为stock1对象的地址

*this//对象

函数括号后面使用const,将this限定为const,这样将不能使用this来修改对象的值

*this//可作为调用对象的别名

对象数组

Stock stocks[SIZE]={

Stock{"aaa",12,23},

Stock("bbb",13,24),

Stock("ccc",14,15),

Stock("ddd",15,23)

};

析构函数后进先出执行

定义成员函数,需要使用作用域解析运算符

类声明的时候可以直接用。

const int Months=12;

double cost[Months];//12只有在创建对对象的时候才能确定

可以用枚举

enum{Months=12};//12是确定的,创建的符号常量

double costs[Months];

static const int Months=12;//可以使用static定义常量

enum class egg{Small,Medium};

enum class t_shirt{Small,Medium};//枚举量的作用域为类

egg choice = egg::Small;//也可使用关键字struct代替class,无论哪种方式,都需要枚举名来限定枚举量

作用域内,枚举不能隐式转换为整型

enum egg_old{small,medium};

未加限定,枚举常量可以被提升

if(king<medium)

加了限定,不能被提升

if(king<egg_old::medium)

必要时可显式类型转换

int Frodo= int(t_shirt::small);

默认情况下,作用域内枚举的底层类型为int

enum class : short pizza{small,medium};

:short将底层类型指定为short,必须是(短,长,普通)整型

抽象数据类型

栈来管理自动变量,添加到堆顶

isalpha(ch);//是否为字母字符

toupper(ch);//转换为大写

Item& 引用可以避免复制大型变量,提高效率

表示已存在变量的别名

相关推荐
懒大王爱吃狼33 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
劲夫学编程34 分钟前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪36 分钟前
孤岛的总面积(Dfs C#
算法·深度优先
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
待磨的钝刨2 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
浮生如梦_3 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
XiaoLeisj4 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
励志成为嵌入式工程师5 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法