第七天(函数——C++编程模块)

本文深入解析C++中函数的返回类型、函数原型、数组与const修饰符的关系,以及如何传递与返回结构体。同时,详细讲解了函数指针的概念、获取函数地址、声明函数指针以及使用函数指针调用函数的方法,并通过实例展示了函数指针的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      昨晚写完笔记,发现已过23:30,今日补之。今天可能还有一份笔记。


2011-10-07(Functions: C++'s Programming Modules)
1、函数的返回值可以是声明的返回值类型或者可转换成该类型的类型。返回值类型不能是数组,其他的的都可以,包括指针、含有数组成员的结构体、对象。
2、函数原型(prototypes)是用于提醒编译器接下来的程序可能要用到什么样的自定义函数,减少出错。一般形式如下:
                                             returnType funcName(parameterList);
C++中必须提供函数原型。有两类函数声明原型的时候要注意:无参数和不指定参数,分别这样声明:
                             void funcName();            //括号里无参数代表void
             void funcName(...);         //不指定参数

3、如果传给函数的是数组,且只读,应该用const修饰,这样在这个函数中,数组就会被看成常量而不能修改,如:

void display(const int [], int); //prototype
void display(const int a[], int size)
{
a[2] = 5; //invalid
}
4、const和指针。
I、一级指针情况。const修饰的对象有两种:修饰变量和修饰指针。前者,很明显,变量本身不能改;后者,修饰的方式有两种,所获效果亦有两种。
①可以将非const变量赋给const指针,有两种形式:
int a = 10;
const int* p1 = &a; //Form I
int* const p2 = &a; //Form II
Form I,对于p1来说,a跟自己一样是const的,不能通过p1来修改a的值,可以改变其指向:
*p1 = 20;           //invalid
a = 20;             //valid
int newA = 100;
p1 = &newA          //valid
Form II,可以通过*p2来修改a的值,但不能改变p2的指向:
*p1 = 20;           //valid
int newA = 100;
p1 = &newA          //invalid
当然还可以同时使用两种形式,效果叠加:
                     const int* const p; 
②不能将const变量赋给非const指针:
                     const int a = 10;
                     int* p = &a; //invalid

如果上述代码可写,意味着可以通过*p来改变a的值,那将a修饰为const将无意义。
II、二级指针情况。一个非const指针不能赋给一个const二级指针,这与变量和一级指针关系不同:
                     int* p;
                     const int** p = &p //invalid

为什么呢?假设上述代码编译可通过,如果我们接下来这样处理:
const int a = 5;      //a constant variable
*pp = &a;             //valid, both *pp and &a is constant. Meanwhile, p = &a
*p = 10;              //valid, p is not const, but you change a's value,which is forbidden
最终结果是将const变量a的值改变。
总结I、II,如果数据本身不是指针,则可以将const数据或非const数据(的地址)赋给const指针,对于非指针,只能将非const数据赋给它。
5、函数与结构体。传递与返回结构体,在C++中又三种方法:按值传递、传递地址和按引用传递。这里按引用传递暂不表。按值传递,就是把结构体看成一个基本数据类型,不同的是它可以用“.”来引用结构体成员。按值传递有个缺点,当结构体很大的时候,将其复制并赋给函数将费去很多时间,所以很多时候都是按地址传递的。比如现在声明一个loc结构体,里面包含成员x,y。再编写函数sum以两个loc为形参,而后返回loc,成员值是形参x,y各自的和。两种实现形式:
#include <iostream>

using namespace std;
struct loc
{
    double x;
    double y;
};
loc sum(loc, loc);
int main()
{
    loc l1 = {3.5, 7.5};
    loc l2 = {2, 3};
    loc l3 = sum(l1, l2);
    cout << "l3.x = " << l3.x << endl;
    cout << "l3.y = " << l3.y << endl;
return 0;
}

loc sum(loc l1, loc l2)
{
    loc l3 = {l1.x + l2.x, l1.y + l2.y};
    return l3;
}
按地址:
#include <iostream>

using namespace std;
struct loc
{
    double x;
    double y;
};
loc* sum(loc*, loc*);
int main()
{
    loc l1 = {3.5, 7.5};
    loc l2 = {2, 3};
    loc* l3 = new loc;
    l3 = sum(&l1, &l2);
    cout << "l3.x = " << l3->x << endl;
    cout << "l3.y = " << l3->y << endl;
    delete l3;
    return 0;
}

loc* sum(loc* l1, loc* l2)
{
    loc* l3 = new loc;
    l3->x = l1->x + l2->x, 
    l3->y = l1->y + l2->y;
    return l3;
}
6、函数指针。函数也有地址,可以将函数A作为另一个函数B的形参,而后使用它。当然这样和在B中直接使用A有什么区别,我现在说不上。但教材提到:如果未提到函数指针,则对C或者C++的函数讨论将是不完整的。显示是对这个方法的一种肯定,有其实用价值。回到正题,在以函数指针为参数,传给另一个函数,需要了解三件事:
I、获取函数的地址。很简单,函数名就是其地址。比如函数Func(),Func就是它的地址。
II、声明函数指针。了解这点就知道了怎么书写函数的参数列表。区别一个函数,需要知道它的返回值类型和参数列表,函数指针类型亦是这样区别的。参考函数原型写法:
                   returnType Func(parameterList);
如果将函数名Func换为*pf,即returnType (*pf) (parameterList),因为*pf是函数,则pf是指向函数的指针。
III、使用函数指针来调用函数。比如某函数接收了一个名为pf的函数指针,在这个函数内使用它,可以采用两种形式(假设pf的返回值和唯一的参数是int):
                   int a = pf(5);         //Form I
                   int b = (*pf) (6);     //Form II

这是两种矛盾的形式。不过在C++均可。
理论过后,举个例子:
#include <iostream>

using namespace std;
void f1(int); //tow basic functions
void f2(int);
//main function to use tow basic functions
void mainf(int, void(*pf) (int));

int main()
{
    mainf(10, f1);
    mainf(50, f2);
    return 0;
}

void f1(int a)
{
    cout << "You use f1 as parameter, ";
    cout << "and f1's parameter value: " << a << endl;
}

void f2(int a)
{
    cout << "You use f2 as parameter, ";
    cout << "and f2's parameter value: " << a << endl;
}

void mainf(int x, void(*pf) (int))
{
    (*pf) (x); //or pf(x)
}
输出: 
             You use f1 as parameter, and f1's parameter value: 10
             You use f2 as parameter, and f2's parameter value: 50

函数mainf的原型表明它可以接受任何以void为返回值(即:无返回值),int为参数列表的函数的地址,这可能比直接调用函数通用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值