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& 引用可以避免复制大型变量,提高效率
表示已存在变量的别名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值