函数名称前面加引用“&”或指针符号“*”的意思

本文介绍了函数指针的基本概念,包括定义、赋值及调用,并解释了函数指针如何提升程序灵活性。同时,还探讨了引用在函数中的应用。

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

学习笔记:

(一)

函数名称前面加引用符号“&”,代表该函数返回值类型是引用。

如:int &operate+(...);

(二)

函数名称前面加指针符号“*”,代表它是函数指针。

函数指针是一个指向函数的指针,函数指针表示一个函数的入口地址。使用函数指针的好处就是在处理“在运行时根据数据的具体状态来选择相应的处理方式”这种需求时更加灵活

定义一个函数指针

指针是变量,所以函数指针也是变量,因此可以使用变量定义的方式来定义函数指针,对于普通的指针,可以这么定义:

int a=10;

int *pa=&a;

这里,pa是一个指向整型的指针,定义这个指针的形式为:

int * pa;

它说明了两点:(1)这是一个指针(2)这是一个指向整型变量的指针

以下给出三个函数指针定义的形式,第一个是C语言的函数指针,第二个和第三个是C++的函数指针的定义形式(都是指向非静态函数成员的函数指针):

int (*pFunction)(float,char,char)=NULL;

int (MyClass::*pMemberFunction)(float,char,char)=NULL;

int (MyClass::*pConstMemberFunction)(float,char,char) const=NULL;


首先,要记住一点的就是形式一定要具备完备性,能表达出我们所要表达的内容,即指向函数这个事实。我们知道普通变量指针可以指向对应类型的任何变量,同样函数指针也应该能够指向对应类型的任何变量。对应的函数类型靠什么来确定?这个我们可以想一下C++的函数重载靠什么来区分不同的函数?这里,函数类型是靠这几个方面来确定的:(1)函数的参数个数(2)函数的参数类型(3)函数的返回值类型。所以我们要设计一种形式,这种形式定义的函数指针能够准确的指向这种函数类型的任何函数。

在C语言中这种形式为:

返回类型 (*函数指针名称)(参数类型,参数类型,参数类型,…);  //注意这是在定义函数指针

嗯,定义变量的形式显然不是我们通常见到的这种形式:

类型名称 变量名称;

因为函数指针不加括号就会产生二义性,就像下面这个:

返回类型 *函数指针名称(参数类型,参数类型,参数类型,…);  //注意这是在定义函数

这样的定义形式定义了一个“返回类型为‘返回类型*’参数为(参数类型,参数类型,参数类型,…)的函数而不是函数指针了。

接下来,对于C++来说,下面这样的定义形式也就不难理解了(加上类名称是为了区分不同类中定义的相同名称的成员函数):

返回类型 (类名称::*函数成员名称)(参数类型,参数类型,参数类型,….

函数的调用规则

一般来说,不用太关注这个问题。调用规则主要是指函数被调用的方式,常见的有_stdcall,_fastcall,_pascal,_cdecl等规则。不同的规则在参数压入堆栈的顺序是不同的,同时在有调用者清理压入堆栈的参数还是由被调用者清理压入堆栈的参数上也是不同的。一般来说,如果你没有显式的说明调用规则的话,编译器会统一按照_cdecl来处理。

 

给函数指针赋值和调用

给函数指针赋值,就是为函数指针指定一个函数名称。这个过程很简单,下面是两个例子:

int func1(float f,int a,int b){return f*a/b;}

int func2(float f,int a,int b){return f*a*b}

然后我们给函数指针pFunction赋值:

pFunction=func1;

pFunction=&func2;

上面这段代码说明了两个问题:(1)一个函数指针可以多次赋值(引用不能这样)(2)取地址符号是可选的,却是推荐使用的。

我们可以思考一下为什么取地址符号是可选的,在普通的指针变量赋值时,如上面所示,需要加取地址符号,而这里却是可选的?这是由于要同时考虑到两个因素(1)避免二义性(2)形式一致性。在普通指针赋值,需要加取地址符号是为了区别于将地址还是将内容赋给指针。而在函数赋值时没有这种考虑,因为这里的语义是清晰的,加上&符号是为了和普通指针变量一致---“因为一致的时候就不容易出错”。

最后我们来使用这个函数,以下两者调用函数的方法都是可以的

pFunction(10.0,’a’,’b’);

(*pFunction)(10.0,’a’,’b’);


同时函数指针可以当参数使用实现回调函数,让程序变得更加简单。


<think>我们正在处理一个关于C++多个概念的详细解释请求。用户引用了两个参考资料,但主要需求是理解列出的C++概念。我们需要逐一解释这些术语,并确保解释清晰、准确。注意:用户要求详细解释,所以每个概念需要适当的阐述和可能的示例。但请注意,我们之前没有对话历史,所以需要完整回答。由于用户提到的概念较多,我们将逐个解释,保持条理清晰。根据系统指令,数学公式使用$...$,但这里主要是代码和概念解释,可能较少涉及数学公式,但如果有数学表达式则按规则处理。同时,回答中需要生成相关问题,最后添引用标识(用户提供了两个引用,我们可以在相关部分引用)。用户要求的概念列表:1.重载(Overloading)2.构造函数(Constructor)3.编译时多态(Compile-timePolymorphism)4.引用符号(ReferenceSymbol)5.类外成员函数定义(Out-of-classMemberFunctionDefinition)6.模板作用(TemplatePurpose)7.运算符重载(OperatorOverloading)8.参数传递方式(ParameterPassingMethods)9.this指针(thisPointer)10.命名空间定义(NamespaceDefinition)11.抽象类与虚函数(AbstractClassandVirtualFunctions)12.静态成员(StaticMembers)13.异常处理(ExceptionHandling)14.指针指向(PointerPointing)15.函数模板定义(FunctionTemplateDefinition)16.参数传递区别(DifferencesinParameterPassing,如值传递、引用传递、指针传递的区别)我们将逐一解释这些概念。注意:由于内容较多,我们可能需要分段并适当使用示例代码(按用户提供的示例格式,使用代码块)。同时,在解释过程中,如果某个概念与用户提供的引用有关,我们会标注引用。开始详细解释:</think> ### C++核心概念详解 #### 1. **重载(Overloading)** 在同一作用域内定义多个同名函数,通过**参数列表不同**(类型/数量/顺序)实现编译时多态。 ```cpp void print(int a) { /*...*/ } // 整型参数版本 void print(double a) { /*...*/ } // 浮点参数版本(参数类型不同) ``` #### 2. **构造函数(Constructor)** 类初始化对象的特殊成员函数,**名称与类名相同**,无返回类型。支持默认构造、拷贝构造等。 ```cpp class Time { public: Time() : minute(0), sec(0) {} // 默认构造函数 Time(int m, int s) : minute(m), sec(s) {} // 带参数构造(重载) }; ``` #### 3. **编译时多态(Compile-time Polymorphism)** 在编译阶段确定调用函数的机制,包括: - **函数重载** - **模板泛型编程** - **运算符重载** #### 4. **引用符号(`&`)** - 声明引用:`int& ref = var;`(必须初始化) - 函数引用:避免拷贝开销,修改实参(区别于指针) #### 5. **类外成员函数定义** 使用作用域解析运算符`::`在类外部定义函数: ```cpp class Time { public: void display(); // 声明 }; void Time::display() { /* 类外实现 */ } // 定义 ``` #### 6. **模板作用** 实现**泛型编程**,编译器自动生成类型特定代码: ```cpp template <typename T> T max(T a, T b) { return (a > b) ? a : b; } // 函数模板 ``` #### 7. **运算符重载** 自定义类对象的运算符行为(保持原有操作数数量): ```cpp Time Time::operator++() { // 前置++重载(引用[2]示例) if (++sec >= 60) { sec -= 60; ++minute; } return *this; } ``` #### 8. **参数传递方式** | 方式 | 特点 | 示例 | |------------|-------------------------------|-----------------------| | 值传递 | 创建拷贝,不影响实参 | `void func(int a)` | | 引用传递 | 操作原始对象,无拷贝开销 | `void func(int& a)` | | 指针传递 | 需解引用,可修改原对象地址 | `void func(int* a)` | #### 9. **`this`指针** 类的非静态成员函数隐含参数,指向**当前对象实例**: ```cpp Time Time::operator++() { this->sec++; // 等价于 sec++ return *this; // 返回当前对象 } ``` #### 10. **命名空间定义(`namespace`)** 避免命名冲突的封装机制: ```cpp namespace MyLib { class Timer { /*...*/ }; // MyLib::Timer } ``` #### 11. **抽象类与虚函数** - **虚函数**:`virtual void draw() = 0;`(实现运行时多态) - **抽象类**:包含纯虚函数的类(不能实例化) - **重写(override)**:子类覆盖基类虚函数(需完全匹配签名,协变除外[^1]) #### 12. **静态成员(`static`)** - **静态变量**:类所有实例共享(存储于全局区) ```cpp class Counter { static int count; // 声明 }; int Counter::count = 0; // 类外初始化 ``` - **静态函数**:无`this`指针,只能访问静态成员 #### 13. **异常处理** `try/catch/throw`机制: ```cpp try { if (error) throw std::runtime_error("Error!"); } catch (const std::exception& e) { std::cerr << e.what(); } ``` #### 14. **指针指向** 指针存储内存地址,需显式解引用(与引用区别): ```cpp int* ptr = new int(10); // 指向动态内存 delete ptr; // 手动释放 ``` #### 15. **函数模板定义** 泛型函数设计,支持类型参数化: ```cpp template <typename T, typename U> auto add(T a, U b) -> decltype(a + b) { return a + b; } ``` #### 16. **参数传递区别总结** | 特性 | 值传递 | 引用传递 | 指针传递 | |------------|-------------|--------------|-------------| | 拷贝开销 | 有 | 无 | 无(指针本身拷贝小) | | 修改原始值 | 否 | 是 | 是(需解引用) | | 空值风险 | 无 | 无(必须初始化)| 有(需判空) | | 典型用途 | 基本类型 | 大型对象/需修改 | 动态内存/兼容C | --- ### 关键概念对比表 | 概念 | 关键点 | 典型场景 | |---------------------|------------------------------------------------------------------------|---------------------------------------| | **重载 vs 重写** | 重载编译时决策(同作用域);重写运行时决策(继承体系+虚函数)[^1] | 多态实现 | | **引用 vs 指针** | 引用不可空、无需解引用指针可重指向、支持算术运算 | 函数参数、避免拷贝 | | **静态 vs 实例成员**| 静态成员属于类;实例成员属于对象 | 计数器、共享配置 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值