3-6 汇总前面的学习经验(第七章)

第七章   函数

内联函数(inline)、类成员函数、重载函数(相同的函数名可以对应多个不同的函数)

返回类型  函数名(形参,形参){函数体}                          求解两个数的最大公约数的方法。

C++使用调用操作符()实现函数调用。

没有任何形参的函数可以用空形参表或含有单个关键字void的形参表来表示。

静态强类型语句,每一次的函数调用,编译都会检查其实参。(实参必须与对应的形参类型相同,或具有可被转换为形参类型)

7.2参数传递

非引用类型的参数通过复制对应的实参实现初始化,不会修改实参的值。     指针形参等同

保护指针指向的值,形参需定义为指向const对象的指针。

const形参

实参仍然以局部副本的形式传递,因而不受限制,const对象  or非const对象都可以进行传递

复制实参的局限性:1、当需要在函数中修改实参的值;2、需要以大型对象作为实参传递时;3、没有办法实现对象的复制(将形参定义为引用或指针类型)

7.5
7.6

引用形参直接关联到其所绑定的实参,而并非局部副本。

定义既返回一个迭代器又返回出现次数的函数
 // returns an iterator that refers to the first occurrence of value
     // the reference parameter occurs contains a second return value
     vector<int>::const_iterator find_val(
         vector<int>::const_iterator beg,             // first element
         vector<int>::const_iterator end,             // one past last element
         int value,                                    // the value we want
         vector<int>::size_type &occurs)              // number of times it occurs
     {
         // res_iter will hold first occurrence, if any
         vector<int>::const_iterator res_iter = end;
         occurs = 0; // set occurrence count parameter
         for ( ; beg != end; ++beg)
             if (*beg == value) {
                 // remember first occurrence of value
                 if (res_iter == end)
                    res_iter = beg;
                 ++occurs; // increment occurrence count
             }
         return res_iter;  // count returned implicitly in occurs
     }

使用引用形参,函数可以直接访问实参对象,无需复制。

非const类型的引用形参只能与完全同类型的非const对象进行关联。

const引用就可以避免复制   不需要修改的引用形参定义为 const 引用。

普通的非 const 引用形参在使用时不太灵活,形参既不能用 const 对象初始化,也不能用字面值或产生右值的表达式实参初始化。

int   *&V1  V1是一个引用,与指向int型对象的指针相关联,V1只是传递进函数的任意指针的别名

Vector形参:为避免复制vector的每一个元素,应考虑将形参声明为引用类型。通过传递只想容器中需要处理的元素的迭代器来传递容器。

数组形参:操作指向数组中的元素的指针来处理数组

数组的特点:1、数组不能复制;2、使用数组名时,数组名自动转化为指向第一个元素的指针。

void printValues(int*)

void printValues(int[])        三种方式相同,形参类型为int*,数组的形式进行表达

void printValues(int[10]) 

通常,将数组形参直接定义为指针要比使用数组语法定义更好。这样就明确地表示,函数操纵的是指向数组元素的指针,而不是数组本身。由于忽略了数组长度,形参定义中如果包含了数组长度则特别容易引起误解

数组实参:

函数操纵的是指针的副本,因此不会修改实参指针的值。然而,函数可通过该指针改变它所指向的数组元素的值。通过指针形参做的任何改变都在修改数组元素本身

不需要修改数组形参的元素时,函数应该将形参定义为指向const对象的指针

形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。编译器将会价差数组的实参大小和形参大小是否匹配

传递给函数的数组的处理:

1、数组旁放置标记进行检测数组的结束。C风格字符串的null指针就是。

2、函数传递两个指针:一个指向第一个元素,另一个指向最后一个元素的下一位置。

3、显示传递数组大小的形参,利用sizeof(数组名称)/sizeof(*数组名称)   *数组名称将会指向数组的第一个元素

mian处理命令行选项:

int main(int argc, char **argv) 第一个形参是传递数组的字符串的个数,第二个参数是数组

在无法列举出传递给函数的所有实参的类型和数目,可以使用省略符形参。

省略符暂停了类型检查的机制,调用函数时,会有0或多个实参,实参的类型未知。

7.3 return语句

return语句用于结束当前正在执行的函数,并将控制权返回给调用此函数的函数。

return;不带返回值,只能返回void的函数。viod函数不必使用return语句,只是为了函数的强制结束。类似于break语句

return expression;带返回值,非void函数必须返回一个值,main()返回的是0值。返回值类型必须和函数返回类型相同,或能隐式转化为函数的返回类型。

在含有 return 语句的循环后没有提供 return 语句是很危险的,因为大部分的编译器不能检测出这个漏洞,运行时会出现什么问题是不确定的。

cstdlib头文件定义了恋歌预处理变量,用于表示程序运行成功与失败

函数返回值初始化临时对象(非引用类型),引用类型的并不复制返回值,而是对象本身。引用指向之前存在的哪个对象?

递归:直接或间接调用自己的函数

函数声明

函数声明由函数返回类型、函数名、形参列表组成函数原型,函数原型描述了函数的接口。形参列表必须有形参类型 。

一个形参具有默认形参,后面所有的形参都必须有默认实参。

函数调用的实参按位置解析,从左到右进行。

局部对象

每个名字都要作用域,该名字的程序文本区;每个对象都有生命期,程序执行过程中对象存在的时间。

只有当定义它的函数被调用才存在的对象--自动对象

一个变量如果位于函数的作用域内,但生命期跨越了这个函数的多次调用,这种变量往往很有用。则应该将这样的对象定义为 static(静态的)

内联函数

inline函数避免函数调用的开销,适用于优化小、几行经常调用的函数。

类的成员函数

类的所有成员必须在类的花括号内声明,但是不必定义。

每个成员函数都有一个额外的、隐含的形参将该成员函数与调用该函数的类对象捆绑在一起。

每个成员函数(除了在第 12.6 节介绍的 static 成员函数外)都有一个额外的、隐含的形参 this

在调用成员函数时,形参 this 初始化为调用函数的对象的地址。

可以理解跟在 Sales_item 成员函数声明的形参表后面的 const 所起的作用了:const 改变了隐含的 this 形参的类型。在调用 total.same_isbn(trans) 时,隐含的 this 形参将是一个指向 total 对象的 const Sales_Item* 类型的指针。

就像如下编写 same_isbn 的函数体一样: const 对象、指向 const 对象的指针或引用只能用于调用其 const 成员函数,如果尝试用它们来调用非 const 成员函数,则是错误的。

total.same_isbn(trans); 

// pseudo-code illustration of how a call to a member function is translated Sales_item::same_isbn(&total, trans); 

// pseudo-code illustration of how the implicit this pointer is used // 

Sales_item::same_isbn(const Sales_item *const this, const Sales_item &rhs) 
const { return (this->isbn == rhs.isbn); } 
用这种方式使用 const 的函数称为常量成员函数。

在成员函数中,不必显式使用this指针访问被调用函数所属对象的成员。

对类的成员任何没有前缀的引用,都假定为指针this实现的引用

 bool same_isbn(const Sales_item &rhs) const
         { return this->isbn == rhs.isbn; }

使用作用域操作符,指明函数时类的作用域范围内定义的。

构造函数constructor是特殊的成员函数,与类同名且没有返回类型。

与成员函数相同,构造函数也有形参表(可能为空)和函数体。

一个类可以有多个构造函数,每个构造函数必须有与其他构造函数不同数目或类型的形参。

构造函数的形参指定了创建类类型对象时使用的初始化式。通常,这些初始化式会用于初始化新创建对象的数据成员。构造函数通常应确保其每个数据成员都完成了初始化。

vector<int> vi; // default constructor: empty vector
string s; // default constructor: empty string
Sales_item item; // default constructor: ???

string 的默认构造函数会产生空字符串上,相当于 ""。

vector 的默认构造函数则生成一个没有元素的 vector 向量对象

Sales_item(): units_sold(0), revenue(0.0) { }

在冒号和花括号之间的代码称为构造函数的初始化列表。构造函数的初始化列表为类的一个或多个数据成员指定初值。它跟在构造函数的形参表之后,以冒号开关。构造函数的初始化式是一系列成员名,每个成员后面是括在圆括号中的初始值。多个成员的初始化用逗号分隔。

如果没有为一个类显式定义任何构造函数,编译器将自动为这个类生成默认构造函数。

内置类型成员的初值依赖于对象如何定义。如果对象在全局作用域中定义(即不在任何函数中)或定义为静态局部对象,则这些成员将被初始化为 0。

复制形参时并不考虑形参是否为 const——函数操纵的只是副本。函数的无法修改实参。结果,既可将 const 对象传递给 const 形参,也可传递给非 const 形参, 形参与 const 形参的等价性仅适用于非引用形参。

有 const 引用形参的函数与有非 const 引用形参的函数是不同的。类似地,如果函数带有指向 const 类型的指针形参,则与带有指向相同类型的非 const 对象的指针形参的函数不相同。

每一个重载函数都应在统一作用域中声明。

函数的声明应放在头文件中。存在多个与实参匹配的函数,但是没有明显的最佳选择,该调用有二义性。

编译器找到与实参最佳匹配的函数,并生成调用该函数的代码
函数重载确定的第一步是确定该调用所考虑的重载函数集合,该集合中的函数称为候选函数。候选函数是与被调函数同名的函数,并且在调用点上,它的声明可见。
第二步是从候选函数中选择一个或多个函数,它们能够用该调用中指定的实参来调用。因此,选出来的函数称为可行函数。可行函数必须满足两个条件:第一,函数的形参个数与该调用的实参个数相同;第二,每一个实参的类型必须与对应形参的类型匹配,或者可被隐式转换为对应的形参类型。
根据实参个数选出潜在的可行函数后,必须检查实参的类型是否与对应的形参类型匹配
函数重载确定的第三步是确定与函数调用中使用的实际参数匹配最佳的可行函数。这个过程考虑函数调用中的每一个实参,选择对应形参与之最匹配的一个或多个可行函数。这里所谓“最佳”的细节将在下一节中解释,其原则是实参类型与形参类型越接近则匹配越佳。因此,实参类型与形参类型之间的精确类型匹配比需要转换的匹配好。
形参、实参类型转换划分等级:
1、实参与形参的类型相同   
2、类型提升实现匹配   较小的整型(short、char类型)提升为int型。
3、标准转换实现的匹配
4、通过类类型转换实现的匹配
虽然无法将整型值传递给枚举类型(unsigned char)的形参,但可以将枚举值传递给整型形参。此时,枚举值被提升为 int 型或更大的整型。
仅当形参是引用或指针时,形参是否为const才有影响

实参为const对象,必须用const形参。非const对象则形参不受限制。

如果实参是 const 对象,则调用带有 const* 类型形参的函数;否则,如果实参不是 const 对象,将调用带有普通指针形参的函数

typedef bool (*cmpFcn)(const string &, const string &); 

当形参以副本传递时,不能基于形参是否为 const 来实现重载 该指针类型为“指向返回 bool 类型并带有两个 const string 引用形参的函数的指针”。在要使用这种函数指针类型时,只需直接使用 cmpFcn 即可,不必每次都把整个类型声明全部写出来。

函数指针 函数指针只能通过同类型的函数或函数指针或 0 值常量表达式进行初始化或赋值 指针的类型必须与重载函数的一个版本精确匹配。

extern void ff(vector<double>);
extern void ff(unsigned int); // which function does pf1 refer to? 
void (*pf1)(unsigned int) = &ff; // ff(unsigned)

// error: no match: invalid parameter list 
void (*pf2)(int) = &ff; 
// error: no match: invalid return type 
double (*pf3)(vector<double>);
pf3 = &ff; 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值