C++ Primer(函数)

来源:互联网 发布:专业网络直播设备 编辑:程序博客网 时间:2024/06/05 17:13

第七章 函数

7.1函数的定义

递归求公约数

int regcd(int v1,int v2)

{
    if(v2!=0)
        return regcd(v2,v1%v2);
    return v1;

}

形参是在函数的形参表中定义的,并由调用函数时传递给函数的实参初始化。

形参是一个表达式,可以是变量或字面值常量,包含一个或几个操作符的表达式。

7.1.1 函数的返回类型可以是内置类型(如int或double)、类类型或复合类型(如int&或string*),还可以是void类型,表示该函数不返回任何值。

函数必须指定返回类型。

7.1.2函数形参表可以为空,但不能省略。如果两个参数具有相同的类型,必须重复声明。

int manip(int v1,int v2);

7.2参数传递

7.2.1 非引用形参

普通的非引用形参通过复制对应的实参实现初始化。

  1. 可以将指向const对象的指针初始化为非const对象,但不可以让指向非const对象的指针指向const对象。
  2. 函数使用非引用的非const形参,既可以给该函数传递const实参也可传递非const的实参。
  3. 不适宜赋值实参的情况:需要在函数总修改实参的值时;需要以大型对象作为实参传递时;没有办法实现对象的复制时。

7.2.2 引用形参

void swap(int &v1,int &v2)

{

int temp=v2; v2=v1; v1=temp;

}

引用形参直接关联到其所绑定的对象。

1.向主函数返回额外的结果

vector<int>::const_iterator find_val(vector<int>::const_iterator beg,
    vector<int>::const_iterator end,
int value,vector<int>::size_type occurs)
{
vector<int>::const_iterator res_iter=end;
occurs=0;
for(;beg!=end;++end)
if(*beg==value){
if(res_iter==end)
res_iter=beg;
++occurs;
}
return res_iter;
}

2.利用const引用避免复制

string对象相当长时

bool isShorter(const string &s1;const string &s2)

{  return s1.size()>s2.size();}

3.将不需要修改的引用形参定义为const引用。

4.传递指向指针的应用

 void ptrswap(int *v1,int *v2)  //v1是一个引用,与指向int型对象的指针相关联。

7.2.3通常函数不应该有vector或其他容器类型的形参,传递迭代器就可以了

7.2.4数组形参

1.由于不能复制数组,所以无法编写使用数组类型形参的函数。数组可以自动转化成指针 ,所以通常通过操纵指向数组中的元素的指针来处理数组。

以下三个等价:都看作是指向数组元素的指针

void fun(int*)// 最好

void fun(int[]) // ok

void fun(int[10])

2.编译器检查数组形参关联的实参是,只会检查实参是不是指针、指针的类型和数组元素的类型是否匹配,不会检查数组的长度。

3.数组实参

数组实参若以非引用形式传递,则会悄悄的转成指针,非引用类型的形参会初始化为相应的的副本,实参是第一个元素的地址,而形参复制的是这个地址的副本,操作的是这个副本,所以不会修改实参指针的值,但是可以修改它们共同指向的对象内容。

所以,数组非引用实参是指针的值传递!

如果不修改数组元素(保护数组)时,那么应该定义为指向const对象的指针

    void fun(const int*)

4.数组引用形参

    void printValues(int (&arr)[10]) { ...... } // 括号是必须的

这个时候,数组实参不会转成指针了,而是传递数组引用本身

必须写大小,实参的大小必须与10匹配

5.多维数组的传递

    void printValues(int (*matrix)[23], int rowSize) { .... }      void printValues(int matrix[][23], introwSize); // 实际上是指针

7.3return语句

7.3.1不带返回值的return语句只能用于返回类型为void的函数。

7.3.2返回类型不是void的函数必须返回一个值,而且这个返回值的类型必须和函数的返回类型相同,或者能隐式转化为函数的返回类型。

1.非void函数必须返回的特殊情况,main函数最后的reutn 0不是必须的

main函数不能递归,不能调用自身

main函数不能重载

2.返回非引用类型在调用函数的地方会将函数返回值复制给临时对象。

3.函数返回引用类型时返回的是对象本身。

4.千万不可返回局部对象的引用,也不能返回局部对象的指针。

7.4函数声明

变量和函数都声明在头文件中,定义在源文件中

源文件包含声明函数的头文件,进行匹配检查

声明在头文件中的好处是确保在所有文件中声明一致,修改方便

1.默认实参,:如果有一个形参有默认实参,那么它后面的所有形参都要有

使用最频繁使用的排在最后

默认实参可以是表达式或有返回值的函数调用

在头文件中声明默认实参

7.5局部对象

1.自动对象

只有当定义它的函数调用时才存在的对象

一般指形参和局部变量,它们在定义它们的语句块结束时撤销

2.静态局部对象

一个变量定义在函数的作用域内,但生命周期跨越了这个函数多次调用,这样的对象定义为static。

输出1--20

size_t count() {

    static size_t c = 0; 

    return++c;

}

int main() {

    for(size_t ix = 0; ix != 20; ++ix) {

       cout<< count() << “ ”;

    }

return 0;

}

7.6内联函数

内联函数在程序的每个调用点上“内联的”展开。

内联机制适用于优化小的、只有几行的而且经常被调用的函数。应该在头文件中定义。

7.7类的成员函数

1.每个成员函数都有一个this形参,是调用该函数的对象的地址

对象实例调用自己的成员函数,将自己传给这个成员函数与之进行绑定

this指针是隐含的,不能明式出现在形参表中

2.常成员函数bool same_isbn(constSales_item&)const;

    total.same_isbn(trans);调用时,则这个this是指向total的const Sales_item*类型的指针, 是个指向const对象的指针,所以这个函数不能改变数据成员

const对象、指向const对象的指针或引用只能用于调用其const成员函数!!反过来,非const的这帮东西可以调用const的成员函数(并非必须是const的对象才能调用)

换句话:const对象不能调用非const成员函数

对于成员函数,声明与定义必须一致,如果要const那么两者都要同时有const

3.类外定义的成员函数的声明必须与其定义一致。

4.构造函数与类同名,而且没有返回类型。一个类可以有多个构造函数,但必须有不同的数目或类型的形参。

5.构造函数的初始化列表在构造函数的形参表之后,以冒号开头,一系列的成员名和圆括号中的初始值,用逗号隔开。

7.8函数重载

名字相同而形参表不同

函数返回类型,最右边形参具有默认实参,以及const的非引用形参不能作为重载的区别标志

int fuc1(int*);

int fuc1(const int*); //重复声明 ,没有error


f(int*)

f(const int*)// 可以重载

而下面的

f(int*)

f(int*const) //不能重载(值传递,副本传递) // 这里是const指针,只有指向const对象的指针作形参才能实现重载

再补充:仅当形参是引用或指针时,形参是否为const才有影响

7.8.3重载的三个步骤

候选函数

选择可行函数

寻找最佳匹配

7.9指向函数的指针

函数指针:bool (*pf)(int); //指向函数的指针

而指针函数:bool *pf(int); // 返回值是指向bool指针

使用typedef简化函数指针

typedefbool (*pf)(int); //pf是一个种指向函数的指针的名字,它所指向的函数有一个int参数,返回值是bool类型

函数指针的初始化和赋值: (三种,0、函数名、&函数名)

第一种:pf fuc1 = 0;

  //等于bool (*fuc1)(int)= 0; // 蓝色部分就是类型

第二种:使用函数名

注意:bool setAge(int); 其中setAge除了用于函数调用外,其他任何使用都将解释为指针: bool(*)(int);

pf fuc2 = setAge; // 使用函数名进行初始化

fuc1 = fuc2; //或赋值

上面直接使用函数名setAge等于在函数名上取地址操作

    pffuc2 = setAge;

    pffuc2 = &setAge; // 两个等价

而使用 pf fuc3(3); //  直接初始化是错的

 

指向不同类型函数的指针不存在转换

 

可以通过函数指针调用函数

fuc2 = setAge;

调用:fuc2(32); // 前提是这个函数指针已经初始化,若是0或未初始化不行

 

函数指针作形参

    voidsamplefuction(const string&, bool(int));

            //函数类型的形参,对应实参将被自动转换为相应的函数指针

    voidsamplefuction(const string&, bool (*)(int));

           //函数指针类型的形参,与上面声明等价

 

    返回类型是指向函数的指针(返回类型可以是函数指针类型,但不可以是函数类型)    后补充:函数ff的返回类型是一个指向”外围”函数的指针

        bool (*ff(int))(int*, int) // 蓝色部分是类型  这句话用在这里是在声明ff这个函数

    ff(int)函数返回一个函数指针,它的类型是bool (*)(int*, int)

    使用typedef使用该定义更加简明易懂

    typedefbool (*PF)(int*, int)

    PFff(int);  // 声明ff这个函数

    举例:

       typedef int func(int*, int);

       void f1(func); // ok,函数类型可以作形参,对应实参将自动转成函数指针

       func f2(int); // error!! 返回类型不能是函数类型,不能自动转成函数指针

       func *f3(int); // ok, 返回类型是函数指针

   

    指向重载函数的指针

    必须精确匹配

    extern void ff(double);

    extern void ff(int); // ok,重载

    void (*pf)(double)= &ff; // ok精确匹配,对应第一个

    int(*pf)(double) = &ff; // error, 返回值不匹配







0 0
原创粉丝点击