程序员人生 网站导航

C++ Primer学习总结 第6章 函数

栏目:php教程时间:2015-03-23 08:17:34
第6章 函数

1.    函数最外层作用域中的局部变量不能使用与函数形参1样的名字,由于它们属于同1个作用域范围.

 

2.    局部静态变量的生命周期: 在全部程序的履行路径第1次经过对象定义语句时初始化,并且直到全部程序终止时才被烧毁,在此期间即便对象所在函数结束履行也不会对它有影响.


 

3.    如果重载的函数的参数只有顶层const区分,那末是毛病的:


如果有底层const区分可以算作重载.

 

4.    如果函数的参数要使用援用(且不会改变援用对象的值),那末应当定义成常量援用. 由于使用普通援用参数会限制函数所能接受的实参类型.


上述例子,如果传递常量int给函数get(),那末就将出错.

还有1个更难发觉的毛病,如果A函数正肯定义形参为常量援用,但是B函数仍然定义形参为普通援用,那末在A函数中使用B函数将出错:

 

5.    如何给函数传递数组形参?

数组也是对象,只不过数组名会自动转化为首元素指针.数组也是有地址的.数组也是有指针的.数组的指针用*解援用便可得到数组本身.

1维数组:

       多维数组: C++实际上没有多维数组,所谓多维数组不过是数组的数组,所以多维数组的第2维(和后面所有维度)的大小都是数组类型的1部份,不能省略.

问题:为何上面输出A数组的值要用(*A)[i],而不能直接A[i]输出?

A是1个指向int[10]数组的指针,那末*A就是1个int[10]的数组.那末(*A)[i]就是这个int[10]数组的第i个元素了.

或可以这么理解其实A是2维数组int a[10][10]的这个a数组中的第1个元素(该元素是1个int[10]数组)的指针,所以*A是a的第1个元素(该元素是1个int[10]数组),所以(*A)[i]是具体的int值元素了.

 

传到print()函数中的是a数组首元素(a[0]数组)的指针,所以如果想输出a[1]的10个元素,需要先A+1,然后*(A+1),然后取每一个元素(*(A+1))[i].



6.    深入讨论:首先使用数组名时,会自动将该数组名转换为该数组首元素的指针. 但是如果我们想使用该数组的指针(而不单单是首元素的指针)该怎样办?

       数组也是对象,对其用&取地址符就能够取得它的地址:

 

7.    对char **A 这类形参,它的含义是甚么?

下面的话“A是1个数组,该数组内都是char*指针不严谨。正确的理解应当是A是1个指向char类型指针的指针。所以我们*A可以得到1个char*指针,至于这个char*指针到底指向1个char数组的元素还是该char*指针仅仅指向1个char还是该char*指针内容根本非法,就不是我们能管的事了,这需要程序的其他部份给予保证。

注意上面程序的实现.

 

8.    如何给函数传递数组援用形参?

数组援用形参要正确写明数组的所有维度.

 

9.    不要返回局部变量的援用或指针(虽然测试简单的程序,这么做常常能得到正确的结果,但是这么做却是严重的毛病):




10.  调用运算符和运算符,箭头运算符优先级相同且都符合左结合律,所以如果函数返回指针,援用或类的对象,我们能用函数调用的结果访问结果对象的成员.

 

11.   C++11支持列表初始化返回值:


 

12.  函数不能返回数组(由于数组不能被拷贝),函数只能返回数组的指针:

 

13.  如何直接定义1个返回数组指针的函数?

上面的括号不能少.

 

14.   const_cast用法:

用法:const_cast<type_id>(expression)

该运算符用来修改类型的(底层)const或volatile属性。除const 或volatile修饰以外, type_idexpression的类型是1样的

1、常量指针被转化成非常量的指针,并且依然指向原来的对象;

2、常量援用被转换成非常量的援用,并且依然指向原来的对象;

 

由上面s3可知const_cast<>()强转还是保持之前的内存地址,


const_cast<>()可使得底层const消失,但是内存地址还是不变的.用了const_cast<>()以后就能够通过b改变之前内存的内容,但是仍然不能通过a去改变. 援用和指针的底层const用强转都是1样的效果.

 

       如果仅用const_cast<>()强转顶层const是无意义的行动,且编译不能通过.


本来就是用a的值去赋给b, 就算a转成int类型,也没有任何区分.

error: invalid use of const_cast with type'int', which is not a pointer, reference, nor a pointer-to-data-member type.

上面是编译器的毛病说明. 说明const_cast只能用于指针或援用的底层const.(第3项不知道是甚么?)

 

15.  如何声明仅具有局部作用域的函数?

在全局定义,但是在局部作用域声明函数,便可使得特定函数仅具有局部作用域.main中对print不可见,由于print的定义在main函数后面,且print的声明在get函数中. 如果print定义在main前面,就算print不声明,main中也能够使用print.

 

16.  函数默许实参,如果函数某个形参有默许值,那末它后面的每一个形参都必须有默许值. 下面是两种函数定义默许值的方式:

方式1:推荐此方式.

方式2


且如果调用含有默许值的函数,所给出的实参总是优先匹配最左侧的形参.   局部变量不能作为默许实参.

 

17.  只能用全局变量作为默许实参.且默许实参的名字在函数声明所在的作用域内解析,而这些名字的求值进程产生在函数调用时.


 

18.  const与constexpr 修饰符:

        我们已知道了字面值常量的值是不可更改的,所以称之为常量。变量是内存中的1块存储空间,我们可以读写里面的内容。但有时候我们也需要1种机制能够禁止随便的修改1个变量的值,这时候候我们就要用到const限定符(const-qualifier)。在定义或声明1个变量的时候,const限定符可以放在我们前面讲过的类型说明符前面或后面表示该变量的值不可被更改。要注意的是,如果变量定义或声明的时候有const限定符,那末1定要进行初始化。由于const变量不可以后来被赋值。对基本数据类型来讲,这也是初始化和赋值的1个细微差别:可以初始化1个const变量,但不可以赋值。例如,

      const限定符在语法上也是类型说明符的1种,但是他不可单独使用,必须和其他的类型说明符搭配使用而表明不可改变(constant)的性质。由于const限定符也是类型说明符,所以const变量和非const变量在C++中其实不是同1种类型,虽然他们之间还是有着千丝万缕的联系,我们以后会详细讲述。你现在要记住的便是int和const int其实不是同1种类型。

 

      C++还提供了1种更加``严格''的constexpr说明符(constexpr-specifier),在变量被声明或定义的时候,如果类型说明符前面或后面用了constexpr说明符,则表明该变量是1个const变量同时该变量必须被初始化。你或许说,这个const不是1样么constexpr更加严格,用来初始化该变量的表达式必须是1个``常数表达式''。也就是说constexpr变量是1个由常数表达式初始化的const变量。关于常数表达式,我们以后还会详细谈起,对基本数据类型来讲,常数表达式是由字面值常量,constexpr限制的变量,和由常数表达式初始化过的const变量组成的表达式。换句话说,常数表达式的值在编译期间就能够肯定。


      constexpr的变量的值必须是编译器在编译的时候就能够肯定的。上例中由于nonconst_var的值在语法上来说,运行期间可能被更改,所以编译期间没法肯定,不属于常数表达式。由于const_var2是由非常数表达式来初始化的,所以const_var2也不是常数表达式。但const_var2本身的声明,定义及初始化是合法的。constexpr比const更严格,用来初始化constexpr_var2和constexpr_var3的也都不是常数表达式,所以他们的定义都是毛病的。

 

19.  函数指针及其用法:

当把函数名作为1个值使用时,该函数自动转化为指针.

 

声明具有函数指针形参的函数:

使用typedef简化函数指针的定义:

C++ primer 第5版中文版 P222⑵23页有更多内容展开.

 

 

 


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐