C++复习(二)

1、二维数组的数组名代表的是指向指针的指针。

2、内联函数不能递归

3、对于模板函数,如果有多个原型,则编译器在选择原型时,非模板版本优先于显式具体化和模板版本,而显式具体化优先于使用模板生成的版本。

4、函数模板实例化和具体化的区别:

  模板实例化 模板具体化
声明 template void Swap<int>(int, int);

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

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

区别 使用Swap()模板生成一个使用特定类型的实例 不要使用Swap()模板生成函数定义,而应使用专门为int 类型显式地定义的函数定义。

注意:试图在同一个文件(或转换单元)中使用同一种类型的显式实例化和显式具体化将出错。

5、对于函数重载、函数模板和函数模板重载,编译器选择使用哪个函数版本呢?

c++有一个良好的策略,来决定函数调用使用哪一个函数定义,尤其是有多个参数时。这个过程称为重载解析。他的大致过程:

(1)、创建候选函数列表。其中包含与被调用函数的名称相同的函数和模板函数。

(2)、使用候选函数列表创建可行函数列表。这些都是参数数目正确的函数,为此有一个隐式装换序列,其中包含实参类型与相应的形参类型完全匹配的情况。

(3)、确定是否有最佳的可行函数,如果有,则使用它,如果没有,则函数调用出错。

编译器查看为使函数调用参数与可行的候选函数的参数匹配所需要进行的转换。通常,从最佳到最差的顺序如下所述:

(1)、完全匹配,但常规函数优先于模板

(2)、提升转换(例如:char和short自动转换为int,float自动转换成double)

(3)、标准转换(例如:int转换为char,long转换为double)

(4)、用户定义的转换,如类声明中定义的转换。

6、关键字decltype的使用(c++11)

//声明:decltype(expression) var;
//1、如果expression 是一个没有用括号括起来的标识符,则var的类型与该标识符的类型相同,包括const等限定符。
ddouble x = 5.5;
double &rx = x;
decltype(x) w; //w是double类型
decltype(rx) u = y; //u是 double& 类型
//2、如果expression是一个函数调用,则var的类型和函数的返回类型相同
int indeed(int);
decltype (indeed(3)) m; //m是int类型
注意:并不会实际调用函数,编译器通过查看函数的原型来获悉返回类型,而无需实际调用函数。
//3、expression是用括号括起来的标识符,则var为指向其类型的引用
double xx = 2.2;
decltype ((xx)) r2 = xx; //xx是 double& 
//4、如果前面的条件都不满足,那么var的类型与expression的类型相同
int j = 3;
int &k = j;
int &n = j;
decltype(j+6) i1; //i1为int类型
decltype(k+n) i2; //i2的类型为int类型

再补充一点:

template<class T1,class T2>
?type gt(T1 x, T2 y)
{
    ...
    return x+y;
}

同样的无法预知将x+y之后的类型。那么就新增了一条语法
 

auto h(int x,float y) ->double

解释:这将返回类型移到了参数声明后面。->double 被称为后置返回类型。其中auto 是一个占位符,表示后置返回类型提供的类型。

也可以这样定义:结合decltype

template<class T1,class T2>
auto gt(T1 x,T2 y) ->decltype(x+y)
{
    ...
    return x+y;
}

现在,decltype 在参数声明后面,因此x和y位于作用域内,可使用他们。

7、register 关键字建议编译器使用CPU寄存器来存储自动变量,旨在提高变量的访问速度。但是在c++11中,register 只是显示的提出变量是自动的。

8、5种变量储存方式

存储描述 持续性 作用域 链接性 如何声明
自动 自动 代码块 在代码块中
寄存器 自动 代码块 在代码块中,使用register(c++11中取消了)
静态,无链接性 静态 代码块 在代码块中,使用static
静态,外部链接性 静态 文件 外部 不在任何函数内
静态,内部链接性 静态 文件 内部 不在任何函数内,使用static

9、链接性为外部的变量简称为外部变量,他们的存储持续性为静态,作用域为整个文件。外部变量是在函数外部定义的,因此对所有函数而言都是外部的。外部变量也称为局部变量。c++有单定义规则,该规则指出,变量只能有一次定义。c++提供两种变量声明,一种是定义,它给变量分配储存空间。一种是声明,它不给变量分配储存空间。

如果要在多个文件中使用外部变量,1、需要在一个文件中包含该变量的定义(可以不加extern修饰),但在使用该变量的其他所有文件中,都必须使用关键字extern声明它。2、需要在一个文件中只有声明没有定义,则必须用extern初始化,然后才能在使用该变量的其他所有文件中使用它(加上extern在使用)。

将static 限定符用于在代码块中定义的变量,使局部变量的存储持续性为静态的。这意味着虽然该变量只在该代码块中可用,但它在该代码块不处于活动状态时任然存在。因此在两次调用之间,静态局部变量的值将保持不变。另外,如果初始化了静态局部变量,则程序只在启动时进行一个初始化。以后在调用该函数时,不会像自动变量那样再次被初始化。

10、总结:

说明符:

auto:在c++11之前,可以在声明中使用关键字auto指出变量是自动变量,但是在c++11中,auto用于自动类型推断。

register 用于声明中指示寄存器存储,而在c++11中,它只是显式的指出变量是自动的。

static 用在作用域为整个文件的声明中时,表示内部链接性;用在局部声明中时,表示局部变量的存储持续性为静态的。

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

thread_local 指出变量的持续性和线程的持续性相同。thread_local 变量之于线程,犹如常规静态变量之于整个程序。

限定符:

volatile在本次线程内,当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后再取变量值  时,就直接从寄存器中取值;当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致。当变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致。当该寄存器在因别的线程等而改变了值,原变量的值不会改变,从而造成应用程序读取的值和实际的变量值不一致。主要是用在:(1)、并行设备的硬件寄存器(如:状态寄存器)  (2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)(3). 多线程应用中被几个任务共享的变量。

那么 volatile 应该解释为“直接存取原始内存地址”。

mutable :即使结构(或类)变量为const,其某个成员也可以被修改。

猜你喜欢

转载自blog.csdn.net/qq_40421919/article/details/86617855