C++ 非类成员函数指针(静态与非静态)、类成员函数指针(静态与非静态)以及这些函数地址的获取

目录

一、函数指针 

1.1. 函数指针的定义方式

二、非类成员函数地址的获取

1.1 普通的全局或静态函数的地址

 三、类成员函数地址的获取

1.1 静态成员函数地址获取

1.2 非静态成员函数地址获取(不好获取)


一、函数指针 

函数存储在内存的代码段(text segment)中,并且它们同样具有地址。如果我们有一个 int test(int a) 函数,那么 test 本身就表示该函数的地址,这一点类似于数组名代表数组的起始地址。

1.1. 函数指针的定义方式

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

例如:

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

在 C++ 中,获取函数的地址打印函数的地址 需要注意指针的类型。下面我们分别介绍 普通函数指针、静态函数指针静态成员函数指针非静态成员函数指针 的情况。并用这些指针打印他们的地址。

二、非类成员函数地址的获取

1.1 普通的全局或静态函数的地址

普通的全局或静态函数的地址可以直接打印:

#include <iostream>

void myFunction() {
    std::cout << "Hello, world!" << std::endl;
}

int main() {
    void (*funcPtr)() = &myFunction;

    // 打印函数指针中存放的值(函数的地址)
    std::cout << "Function pointer address: " << (void*)funcPtr << std::endl;

    return 0;
}

输出示例

Function pointer address: 0x401550

📌 说明

  • funcPtr 是普通函数的指针,可以直接转换成 void* 进行打印。

关键点解析

  1. myFunction 是一个函数,它存放在代码段(text segment)中,并且具有固定的地址。
  2. funcPtr 是一个指向 myFunction 的指针,即 funcPtr 存储的是 myFunction 的地址。
  3. (void*)funcPtr 的实际含义
    • funcPtr 存储的是 myFunction 的地址。
    • (void*)funcPtr 进行类型转换,使 funcPtrvoid* 的形式打印出来。
    • 由于 funcPtr 存储的就是 myFunction 的地址,所以 std::cout << (void*)funcPtr; 打印的是 myFunction 的地址

最终结论

打印的结果是 myFunction 的地址,而不是 funcPtr 本身的地址。

如果想打印 funcPtr 指针本身的地址(即存放 funcPtr 的内存地址),可以使用:

std::cout << "Address of funcPtr itself: " << &funcPtr << std::endl;
这样才能看到 funcPtr 变量本身存储在内存中的地址。🚀

 三、类成员函数地址的获取

1.1 静态成员函数地址获取

 静态成员函数和普通函数类似,它们不依赖对象,可以直接获取地址:

#include <iostream>

class A {
public:
    static void staticFunc() {
        std::cout << "Static function called!" << std::endl;
    }
};

int main() {
    void (*funcPtr)() = &A::staticFunc;

    // 打印静态成员函数的地址
    std::cout << "Static function pointer address: " << (void*)funcPtr << std::endl;

    return 0;
}

输出: 

Static function pointer address: 0x402cf0

 📌 说明

  • 静态成员函数本质上和普通函数一样,可以直接 void* 转换后打印。

1.2 非静态成员函数地址获取(不好获取)

为什么非静态成员函数指针不能直接打印?

非静态成员函数指针与普通函数指针(包括静态成员函数指针)有所不同,原因主要在于 它们的内存布局和调用机制

我们可以从以下几个方面来理解:


1. 非静态成员函数的特殊性

  • 非静态成员函数 是类的一部分,它们依赖于类的实例,也就是说,它们的调用需要绑定一个对象(或者通过 this 指针)。这与普通的全局或静态函数不同,后者不依赖于对象。

  • 由于非静态成员函数指针不仅包含函数的地址,还需要包含与对象相关的附加信息,比如 this 指针,它指向当前对象。因此,非静态成员函数指针包含了更多信息,并不是单纯的代码地址。


2. 内存布局

在内存中,普通函数指针(比如 void (*funcPtr)())和非静态成员函数指针的布局是不同的。普通函数指针直接指向代码段(函数的起始位置),而非静态成员函数指针则可能存储:

  • 函数的代码地址
  • 其他信息,如与该函数关联的类的实例(通过 this 指针)。

因此,非静态成员函数指针不仅仅是一个普通的地址,它包含更多的内存结构,不能直接用普通的输出方式打印。


3. std::cout 和成员函数指针

std::cout 默认并没有定义如何输出成员函数指针。因为成员函数指针是一个复杂的类型,包含了函数地址以及其他内部信息,而 std::cout 是设计来打印普通指针和基本数据类型的,不能直接理解和处理这种复合类型。


4. 如何正确处理非静态成员函数指针

对于非静态成员函数指针,我们可以通过以下方法来访问和使用它们:

1) 使用 printf 打印函数指针

如果你想打印非静态成员函数指针的地址,可以使用 printf

printf("%p", *(void**)&funcPtr);

通过类型转换,你可以将非静态成员函数指针转换为 void* 类型,这样就能够获取其底层地址。

2) 使用 std::cout 打印成员函数指针

成员函数指针不能直接转换为 void*,但是你可以通过 std::cout 来打印它:

std::cout << funcPtr << std::endl;

某些编译器和平台可能允许直接输出成员函数指针,但这种行为不符合 C++ 标准,可能会导致平台依赖性或未定义行为。


5. 总结

  • 非静态成员函数指针是特殊的,包含了对函数代码地址的引用和与对象的关联,因此不能直接像普通函数指针那样直接打印。
  • std::cout 不支持直接输出成员函数指针,因为它包含了更多的信息,而不仅仅是地址。
  • 如果需要打印,使用 printf("%p", *(void**)&funcPtr) 可以正确打印函数指针的底层地址。

这些设计和限制源于 C++ 的内存管理方式和面向对象特性,尤其是与对象实例(this)的绑定。

推荐阅读:

C++ 函数指针 & 类成员函数指针 | 菜鸟教程
C++如何打印类成员函数的地址_c++打印函数地址-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值