在讲函数指针之前,我们需要先理解一个概念:编译器是怎么识别并调用函数的。 众所周知,在C/C++程序编译时,内存有四个功能分区: 1)代码区: 存放函数。 2)数据区: 存放静态数据以及全局变量。 3)堆区 存放指针。 4)栈区 存放局部变量。
既然函数也是被存放在内存中的,那函数肯定也就如同其他数据一样,在内存中占有相应的内存单元,而每个内存单元都有一个入口地址。所以,不难想到,程序在运行期间调用一个函数,必定是先寻到这个函数的入口地址,然后才能执行其对应的功能。我们也就可以通过指针直接指向某个函数的入口地址,从而通过指针调用这个函数,这就是函数指针。
函数指针的使用
普通函数指针: 函数指针和变量指针的使用不太一样,函数指针我们通过如下方式声明:
(函数返回值类型) (指针) (函数的形参列表)
示例程序:
#include <iostream>
using namespace std;
void sayName(string name) {
cout << "I am " << name << endl;
}
int main() {
void (*p)(string name) = &sayName;
p("Bob");
return 0;
}
以上程序运行结果输出:
I am Bob
使一个函数指针指向函数时,我们可以只使用对应函数名赋值,不过在函数名前加取地址符号 & 也是没问题的(建议加上)。
类成员函数指针: 如果要使一个函数指针指向类的 public 成员函数,声明的方法也和普通函数指针有所不同,因为我们需要说明这个类成员函数指针指向的函数属于哪个类:
(函数返回值类型) (类名 :: 指针) (函数形参列表)*
示例程序:
#include <iostream>
using namespace std;
class A {
public:
A(string name):name_(name) {}
public:
void sayName() {
cout << "I am " << name_ << endl;
}
private:
string name_;
};
int main() {
A a("Alice");
A b("Bob");
void (A::*p)() = &A::sayName;
(a.*p)();
(b.*p)();
return 0;
}
以上程序运行结果输出:
I am Alice
I am Bob
在通过类成员函数指针调用时,也和普通函数指针的使用不太一样,因为我们需要说明这个类成员函数指针指向这个类的哪一个对象,因为同一个类的不同实例对象,对应成员函数的执行结果也可能是不同的(应该说可能是相同的,因为大部分情况下都应该是不同的才对)。 调用时语法如下:
(实例对象名 . 类成员函数指针) (实参列表)
上面的程序中,我们定义了一个指向 A 类成员的指针 p , 我们先通过 p 调用了 A 类实例对象 a 的 sayName ;然后我们再通过 p 调用了 A 类实例对象 b 的 sayName 。
并且,函数指针也是支持多态的 。
示例程序:
#include <iostream>
using namespace std;
class A {
public:
A(string name):name_(name) {}
public:
virtual void sayName() {
cout << "I am " << name_ << endl;
}
protected:
string name_;
};
class B:public A {
public:
B(string name, string number):A(name), number_(number) {}
public:
void sayName() {
cout << "I am " << name_ << " and ";
cout << "My number is " << number_ << endl;
}
private:
string number_;
};
int main() {
A a("Alice");
A b("Bob");
B c("Sandy", "123456");
void (A::*p)() = &A::sayName;
(a.*p)();
(b.*p)();
(c.*p)();
return 0;
}
以上程序运行结果输出:
I am Alice
I am Bob
I am Sandy and My number is 123456
上面的程序中,我将 A 的 sayName 函数定义为了虚函数,使新定义的类 B 继承自 A ,并在 B 中实现了与其父类 A 中不同的 sayName 函数。此时的 A 类成员函数指针依旧可以指向其子类 B 的 sayName 函数,并且调用的是 B 中实现的 sayName 函数。
毕。