菜鸟教程 -- 学的不仅是技术,更是梦想!

C++ 函数指针 & 类成员函数指针

分类 编程技术


一、函数指针

函数存放在内存的代码区域内,它们同样有地址.如果我们有一个 int test(int a) 的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。

1、函数指针的定义方式

data_types (*func_pointer)( data_types arg1, data_types arg2, ...,data_types argn);

例如:

int (*fp)(int a); // 这里就定义了一个指向函数(这个函数参数仅仅为一个 int 类型,函数返回值是 int 类型)的指针 fp。

实例

inttest(inta){returna; }intmain(intargc, constchar * argv[]){int(*fp)(inta); fp = test; cout<<fp(2)<<endl; return0; }

注意:函数指针所指向的函数一定要保持函数的返回值类型,函数参数个数,类型一致。

2、typedef 定义可以简化函数指针的定义

实例

inttest(inta){returna; }intmain(intargc, constchar * argv[]){typedefint(*fp)(inta); fpf = test; cout<<f(2)<<endl; return0; }

3、 函数指针同样是可以作为参数传递给函数的

实例

inttest(inta){returna-1; }inttest2(int(*fun)(int),intb){intc = fun(10)+b; returnc; }intmain(intargc, constchar * argv[]){typedefint(*fp)(inta); fpf = test; cout<<test2(f, 1)<<endl; // 调用 test2 的时候,把test函数的地址作为参数传递给了 test2return0; }

执行以上代码,输出结果为:

10

4、利用函数指针,我们可以构成函数指针数组,更明确点的说法是构成指向函数的指针数组。

实例

voidt1(){cout<<"test1"<<endl;}voidt2(){cout<<"test2"<<endl;}voidt3(){cout<<"test3"<<endl;}intmain(intargc, constchar * argv[]){typedefvoid(*fp)(void); fpb[] = {t1,t2,t3}; // b[] 为一个指向函数的指针数组b[0](); // 利用指向函数的指针数组进行下标操作就可以进行函数的间接调用了return0; }

二、指向类成员函数的函数指针

定义:类成员函数指针(member function pointer),是 C++ 语言的一类指针数据类型,用于存储一个指定类具有给定的形参列表与返回值类型的成员函数的访问信息。

基本上要注意的有两点:

  • 1、函数指针赋值要使用 &
  • 2、使用 .* (实例对象)或者 ->*(实例对象指针)调用类成员函数指针所指向的函数

下面看两个例子:

A) 类成员函数指针指向类中的非静态成员函数

对于 nonstatic member function (非静态成员函数)取地址,获得该函数在内存中的实际地址

对于 virtual function(虚函数), 其地址在编译时期是未知的,所以对于 virtual member function(虚成员函数)取其地址,所能获得的只是一个索引值

实例

//指向类成员函数的函数指针#include<iostream>#include<cstdio>usingnamespacestd; classA{public: A(intaa = 0):a(aa){} ~A(){}voidsetA(intaa = 1){a = aa; }virtualvoidprint(){cout << "A: " << a << endl; }virtualvoidprinta(){cout << "A1: " << a << endl; }private: inta; }; classB:publicA{public: B():A(), b(0){}B(intaa, intbb):A(aa), b(bb){} ~B(){}virtualvoidprint(){A::print(); cout << "B: " << b << endl; }virtualvoidprinta(){A::printa(); cout << "B: " << b << endl; }private: intb; }; intmain(void){Aa; Bb; void(A::*ptr)(int) = &A::setA; A* pa = &a; //对于非虚函数,返回其在内存的真实地址printf("A::set(): %p\n", &A::setA); //对于虚函数, 返回其在虚函数表的偏移位置printf("B::print(): %p\n", &A::print); printf("B::print(): %p\n", &A::printa); a.print(); a.setA(10); a.print(); a.setA(100); a.print(); //对于指向类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用(pa->*ptr)(1000); a.print(); (a.*ptr)(10000); a.print(); return0; }

执行以上代码,输出结果为:

A::set(): 0x8048a38
B::print(): 0x1
B::print(): 0x5
A: 0
A: 10
A: 100
A: 1000
A: 10000

B) 类成员函数指针指向类中的静态成员函数

实例

#include<iostream>usingnamespacestd; classA{public: //p1是一个指向非static成员函数的函数指针void(A::*p1)(void); //p2是一个指向static成员函数的函数指针void(*p2)(void); A(){/*对 **指向非static成员函数的指针 **和 **指向static成员函数的指针 **的变量的赋值方式是一样的,都是&ClassName::memberVariable形式 **区别在于: **对p1只能用非static成员函数赋值 **对p2只能用static成员函数赋值 ** **再有,赋值时如果直接&memberVariable,则在VS中报"编译器错误 C2276" **参见:http://msdn.microsoft.com/zh-cn/library/850cstw1.aspx */p1 =&A::funa; //函数指针赋值一定要使用 &p2 =&A::funb; //p1 =&A::funb;//error//p2 =&A::funa;//error//p1=&funa;//error,编译器错误 C2276//p2=&funb;//error,编译器错误 C2276}voidfuna(void){puts("A"); }staticvoidfunb(void){puts("B"); }}; intmain(){Aa; //p是指向A中非static成员函数的函数指针void(A::*p)(void); (a.*a.p1)(); //打印 A//使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数p = a.p1; (a.*p)();//打印 AA *b = &a; (b->*p)(); //打印 A/*尽管a.p2本身是个非static变量,但是a.p2是指向static函数的函数指针, **所以下面这就话是错的! */// p = a.p2;//errorvoid(*pp)(void); pp = &A::funb; pp(); //打印 Breturn0; }

总结

类成员函数指针与普通函数指针不是一码事。前者要用 .* 与 ->* 运算符来使用,而后者可以用 * 运算符(称为"解引用"dereference,或称"间址"indirection)。

普通函数指针实际上保存的是函数体的开始地址,因此也称"代码指针",以区别于 C/C++ 最常用的数据指针。

而类成员函数指针就不仅仅是类成员函数的内存起始地址,还需要能解决因为 C++ 的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。

原文地址:https://blog.csdn.net/crayondeng/article/details/16868351

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址
ADO 教程 AI Agent 教程 AI 入门教程 Ajax 教程 Android 教程 Angular2 教程 AngularJS 教程 AppML 教程 ASP 教程 ASP.NET 教程 Bootstrap 教程 Bootstrap4 教程 Bootstrap5 教程 C 教程 C# 教程 C++ 教程 Chart.js 教程 Claude Code 教程 CMake 教程 Codex 教程 CSS 参考手册 CSS 教程 CSS3 教程 Cursor 教程 Dart 教程 Dash 教程 Django 教程 Docker 教程 DTD 教程 ECharts 教程 Eclipse 教程 Electron 教程 FastAPI 教程 Firebug 教程 Flask 教程 Flutter 教程 Font Awesome 图标 Foundation 教程 Git 教程 Go 语言教程 Google 地图 API 教程 Hermes Agent Highcharts 教程 HTML DOM 教程 HTML 参考手册 HTML 字符集 HTML 教程 HTTP 教程 ionic 教程 iOS 教程 Java 教程 JavaScript 参考手册 Javascript 教程 jQuery EasyUI 教程 jQuery Mobile 教程 jQuery UI 教程 jQuery 教程 JSON 教程 JSP 教程 Julia 教程 Jupyter Notebook 教程 Kotlin 教程 LangChain 教程 LaTeX 教程 Linux 教程 Lua 教程 Markdown 教程 Matplotlib 教程 Maven 教程 Memcached 教程 MongoDB 教程 MySQL 教程 Next.js 教程 NLP 教程 Node.js 教程 NumPy 教程 Obsidian 教程 Ollama 教程 OpenCode 教程 OpenCV 教程 Pandas 教程 Perl 教程 PHP 教程 Pillow 教程 Playwright 教程 PostgreSQL 教程 PowerShell Pycharm 教程 Python 3 教程 Python 基础教程 Python 设计模式 Python 量化交易 PyTorch 教程 R 教程 RDF 教程 React 教程 Redis 教程 RESTful API RSS 教程 Ruby 教程 Rust 教程 Sass 教程 Scala 教程 SciPy 教程 Selenium 教程 Servlet 教程 Skills 教程 Sklearn 教程 SOAP 教程 SQL 教程 SQLite 教程 SVG 教程 SVN 教程 Swagger 教程 Swift 教程 Tailwind CSS 教程 TCP/IP 教程 TensorFlow 教程 TypeScript 教程 uni-app 教程 VBScript 教程 Vibe Coding 教程 VSCode 教程 Vue.js 教程 Vue3 教程 W3C 教程 Web Service 教程 WSDL 教程 XLink 教程 XML DOM 教程 XML Schema 教程 XML 教程 XPath 教程 XQuery 教程 XSLFO 教程 XSLT 教程 Zig 教程 数据结构 机器学习 正则表达式 汇编语言 测验 浏览器 网站品质 网站建设指南 网站服务器教程 网络协议 设计模式

AltStyle によって変換されたページ (->オリジナル) /