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

第6章 函数

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

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

3.    如果重载的函数的参数只有顶层const区别,那么是错误的:

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

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

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

还有一个更难察觉的错误,如果A函数正确定义形参为常量引用,但是B函数依然定义形参为普通引用,那么在A函数中使用B函数将出错:

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

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

一维数组:

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

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

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

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

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

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

数组也是对象,对其用&取地址符就可以获得它的地址:

7.    对于char **A 这种形参,它的含义是什么?

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

注意上面程序的实现.

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

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

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

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

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

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

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

上面的括号不能少.

14.   const_cast用法:

用法:const_cast<type_id>(expression)

该运算符用来修改类型的(底层)const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的

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

二、常量引用被转换成非常量的引用,并且仍然指向原来的对象;

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

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

如果仅用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.(第三项不知道是什么?)

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

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

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

方式一:推荐此方式.

方式二

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

 

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

18.  const与constexpr 修饰符:

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

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

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

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

19.  函数指针及其用法:

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

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

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

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

时间: 2024-12-16 19:48:19

C++ Primer学习总结 第6章 函数的相关文章

【C语言学习】《C Primer Plus》第9章 函数

学习总结 1.函数有利于我们可以省去重复的代码,函数可以使程序更加模块化,从而有利于程序的阅读.修改和完善.我们在系统设计或架构设计的时候,往往追求的是模块化.组件化.松耦合,而函数就是其代码的表现.许多程序员喜欢把函数看作“黑盒子”,即对应一定的输入产生特定的结果或返回某个数值,而黑盒子的内部行为并不需要考虑,然而有助于把精力投入到程序整体设计而不是其实现细节.按照C设计原则,我们不应为每个任务编写一个单独的函数,而应该尽量把函数的功能进行抽象设计到达通用目的. 2.函数的组成部分有函数类型.

C++ Primer学习总结 第7章 类

第7章 类 1.    引入const成员函数(C++ Primer P231-232) C++类的常量对象是无法调用非const成员函数的,如果想让常量对象调用某个成员函数,必须声明成const: 2.     一个类的尾后const成员函数如果返回*this,那么其返回类型必然是const 类名 & 前面这个const是不能少的.否则无法通过编译. 3.    默认构造函数P235-236 编译器只有在发现类中不包含任何构造函数的情况下,才会为我们合成一个默认的构造函数,且该函数对于类中的成

C++ Primer学习总结 第14章 操作重载与类型转换

第14章 操作重载与类型转换 1.    可以直接调用重载的运算符函数. 但是如果对于一个运算符比如+号,既有重载的成员函数,又有重载的非成员函数,那么此时如果直接使用+号,那么就会出现错误. 因为编译器不知道要调用那个运算符. 2.     逗号,运算符 逻辑与&&运算符 逻辑或||运算符不建议重载. 因为上述3种运算符本身是有求值顺序和短路求值特性(&&和||有短路求值特性)的. 但是重载后的运算符本质上是一次函数调用, 所以求值顺序和短路求值特性都会消失. 注意上面第

C++ Primer学习总结 第15章 面向对象程序设计

第15章 面向对象程序设计 1.    构造基类和派生类. 其中A类是基类,B类是派生类.派生类的构造函数必须重新写过,不能继承.(因为毕竟两个类的类名都不一样,不可能构造函数继承)只继承其他的成员函数和成员变量. 派生类可以覆盖基类的虚函数,但是也可以选择不覆盖(即直接使用父类的函数版本)比例A类的print_1()虚函数就没有被覆盖. 基类的静态成员:如果基类有一个静态成员,那么基类和所有派生类都共同拥有这仅有的一个静态成员. 2.    基类的虚函数默认实参最好与派生类的虚函数默认实参一致

C++ Primer学习总结 第10章 泛型算法

第10章 泛型算法 1.    find()泛型算法使用示例: 2.    只读算法accumulate:对所给范围的元素求和并返回. 注意accumulate的第3个参数决定着它的返回类型. 即如果第3个参数是double,就算迭代器里都是int,最终还是返回double类型的数. 3.    只读算法equal:比较前两个迭代器表示范围的所有元素是否与第3个迭代器表示的对应位置的元素都相同,如果相同返回true.两个容器类型可以不同,保存的元素类型也可以不同,只要元素之间可以比较即可.如st

C++ Primer学习总结 第11章 关联容器

第11章 关联容器 1.    使用map的简单例子: 运行结果为: 2.    初始化map和set: 3.    set与multiset的区别: 4.    使用map和set时,其元素类型必须是定义了严格弱序的(即定义了<号比较的),如果元素类型没有定义<号操作也可以通过外部函数来比较: 5.    pair类型:pair是一个用来生成特定类型的模板. pair的默认构造函数对数据成员进行值初始化. 6.    遍历map和set关联容器: 7.    如何往set和map中添加指定元

C++ Primer学习总结 第12章 动态内存

第12章 动态内存 1.    申请并使用shared_ptr.  P400 2.    shared_ptr计数. P402 赋值, 拷贝, 向函数传递一个智能指针, 或函数返回一个智能指针都会增加当前智能指针的计数. 3.    不同对象间利用智能指针共享数据的例子. 4.    使用new来动态申请内存. P407 默认情况下,new申请的内存对象都是默认初始化的. 5.    new申请的const对象必须初始化. P408 如果申请内置类型, 那么必须用括号()初始化. 如果申请类类型

C++ Primer学习总结 第13章 拷贝控制

第13章 拷贝控制 1.    什么是拷贝构造函数? P440 如果一个类的构造函数的第一个参数是自己类类型的引用, 且所有其他参数都有默认值, 那么这就是一个拷贝构造函数. 2.    拷贝初始化和直接初始化.  P441 如果初始化的时候使用等号"="来初始化一个对象, 那么就是拷贝初始化. 相反, 如果初始化时, 没有用等号"=", 那么就是直接初始化. 如果是拷贝初始化, 那么用的一定是拷贝构造函数(也有可能用移动构造函数). 如果是直接初始化, 那么就用参

C++ Primer学习总结 第9章 顺序容器

第9章 顺序容器 1.    顺序容器如果有一个只需要容器大小参数的默认构造函数,该函数使用的是元素的默认构造函数来构造每个元素对象,如果该容器的元素没有默认构造函数,那么就不能使用这个容器的该构造函数P294: 2.    容器进行拷贝初始化时,两个容器的元素必须同类型. 但是如果列表初始化,或迭代器范围初始化容器,那么只要求列表中元素或迭代器所指元素可以转化为容器的元素即可. 3.    容器类型可以直接通过=号赋值(包括array容器数组类型): 注意:assign仅适用于顺序容器(但不适