1 函数声明
C++ 函数声明的完整范式可以表示为:
[存储类说明符] [内联说明符] [虚函数说明符] [constexpr] [静态断言]
返回类型 [调用约定] 函数名 (参数列表) [const] [volatile] [引用限定符]
[异常说明] [尾置返回类型] [= default/delete/0];1.1 详细解析
1.1.1 存储类说明符
static int func(); // 静态存储
extern int func(); // 外部链接
inline int func(); // 内联建议1.1.2 CV 限定符和函数说明符
virtual int func(); // 虚函数
constexpr int func(); // 编译期计算
mutable int func(); // 可变(少用)1.1.3 返回类型
int func(); // 基本类型
auto func() -> int; // 尾置返回类型
template<typename T>
auto func() -> decltype(T{}); // 推导返回类型1.1.4 调用约定(主要在 Windows)
int __cdecl func(); // C调用约定
int __stdcall func(); // 标准调用约定
int __fastcall func(); // 快速调用约定1.1.5 参数列表
int func(); // 无参数
int func(int a, double b); // 普通参数
int func(int a = 10); // 默认参数
int func(const int& a); // 引用参数
int func(int&& a); // 右值引用参数
template<typename... Args>
int func(Args... args); // 可变参数模板
int func(int a, ...); // C风格可变参数1.1.6 CV 限定符(成员函数)
class MyClass {
int func() const; // 常量成员函数
int func() volatile; // volatile成员函数
int func() const volatile; // 同时具有两种限定
};1.1.7 引用限定符(C++11)
class MyClass {
int func() &; // 只能被左值对象调用
int func() &&; // 只能被右值对象调用
int func() const &; // 常量左值
int func() const &&; // 常量右值
};1.1.8 异常说明
int func() noexcept; // 不抛出异常
int func() noexcept(true); // 不抛出异常
int func() noexcept(false); // 可能抛出异常
int func() throw(); // 旧式,不抛出异常(已废弃)
int func() throw(std::exception); // 旧式,指定异常类型(已废弃)1.1.9 特殊成员函数说明符
class MyClass {
MyClass() = default; // 默认实现
MyClass(const MyClass&) = delete; // 删除函数
virtual ~MyClass() = 0; // 纯虚函数
};1.1.10 尾置返回类型(C++11)
auto func(int a, int b) -> int; // 尾置返回类型
auto func() -> decltype(auto); // 自动推导
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u); // 模板中的尾置返回类型1.2 完整示例
class MyClass {
public:
// 最复杂的函数声明示例
static inline virtual constexpr
auto complexFunc(const int& a, double&& b, int c = 10) const noexcept
-> decltype(a + b + c);
// 成员函数的完整形式
mutable virtual auto memberFunc(int a) & noexcept(false) -> int = 0;
// 普通函数的完整形式
static constexpr inline auto staticFunc(int a, double b) noexcept -> double {
return a * b;
}
};
// 全局函数的完整形式
extern inline constexpr auto globalFunc(int a) noexcept -> int;
// 函数指针的完整形式
auto (*funcPtr)(int, double) noexcept -> int = nullptr;1.3 注意事项
- 并非所有组合都有效:某些说明符互相冲突
- 语法顺序很重要:虽然某些说明符可以调换位置,但建议遵循标准顺序
- C++ 版本差异:一些特性需要特定 C++ 版本支持
- 编译器支持:某些特性可能需要特定编译器支持
这就是 C++ 函数声明的完整语法范式,实际使用中很少会用到所有这些特性。
2 函数指针声明
2.1 基本函数指针语法
函数指针的基本范式是:
返回类型 (*指针名)(参数列表)2.2 对比示例
// 普通函数声明
int func(int a, double b);
// 函数指针声明 - 不是简单的加*
int (*funcPtr)(int a, double b); // 正确
int *funcPtr(int a, double b); // 错误!这是返回int*的函数2.3 为什么不能简单加 *?
因为运算符优先级的问题:
int *funcPtr(int a); // 解析为:int* funcPtr(int a) - 返回指针的函数
int (*funcPtr)(int a); // 解析为:指向函数的指针2.4 复杂函数指针示例
2.4.1 带 CV 限定符的成员函数指针
class MyClass {
public:
int normalFunc(int a);
int constFunc(int a) const;
int volatileFunc(int a) volatile;
};
// 成员函数指针
int (MyClass::*memberPtr)(int) = &MyClass::normalFunc;
int (MyClass::*constMemberPtr)(int) const = &MyClass::constFunc;
int (MyClass::*volatileMemberPtr)(int) volatile = &MyClass::volatileFunc;2.4.2 带异常说明的函数指针
// 函数指针包含异常说明
int (*noexceptPtr)(int) noexcept = nullptr;
int (*throwPtr)(int) = nullptr; // 可能抛出异常的函数指针2.4.3 复杂的函数指针类型
// 指向返回函数指针的函数的指针
int (*(*complexPtr)(int))(double);
// 解析:
// complexPtr 是一个指针
// 指向一个函数,该函数接受int参数
// 返回一个函数指针,该函数指针指向接受double参数、返回int的函数2.4.4 数组中的函数指针
// 函数指针数组
int (*funcArray[10])(int, double);
// 指向函数指针数组的指针
int (*(*arrayPtr)[10])(int, double);2.5 使用 typedef/using 简化
// 使用typedef简化复杂函数指针
typedef int (*FuncPtr)(int, double);
typedef int (MyClass::*MemberPtr)(int) const;
// C++11 using别名
using FuncPtr = int(*)(int, double);
using MemberPtr = int(MyClass::*)(int) const;
// 使用别名
FuncPtr ptr = someFunction;
MemberPtr memPtr = &MyClass::someMethod;2.6 函数指针的完整语法范式
[返回类型] ([类名::] *[指针名]) ([参数列表]) [CV限定符] [异常说明]2.6.1 完整示例
class MyClass {
public:
static int staticFunc(int a) noexcept;
int memberFunc(int a, double b) const;
virtual int virtualFunc(int a) volatile;
};
// 各种函数指针声明
int (*staticPtr)(int) noexcept = &MyClass::staticFunc;
int (MyClass::*memberPtr)(int, double) const = &MyClass::memberFunc;
int (MyClass::*virtualPtr)(int) volatile = &MyClass::virtualFunc;
// 复杂的函数指针
auto (*complexPtr)(int) noexcept -> int = [](int x) noexcept -> int { return x; };2.7 实际使用建议
由于函数指针语法复杂,实际开发中建议:
- 使用类型别名
using Callback = std::function<int(int, double)>; // 更灵活
using FuncPtr = int(*)(int, double); // 纯函数指针- 使用 auto 推导
auto funcPtr = &someFunction; // 让编译器推导类型- 使用 std::function
std::function<int(int, double)> callback = someFunction; // 更通用所以函数指针绝不是简单地在函数名前加 *,而是需要用括号明确优先级,并且可能包含各种限定符。
3 成员函数指针作为成员变量 vs 返回成员函数指针的成员函数?
TL;DR:看括号的位置 - 如果函数名后面直接跟括号,就是返回函数指针的函数;如果是变量名,就是函数指针成员变量。
示例:
#include <iostream>
class Calculator {
private:
// 成员函数指针作为成员变量
int (Calculator::*operation)(int, int);
// 返回成员函数指针的成员函数
int (Calculator::* getOperation(char op))(int, int);
public:
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
void setOperation(char op) {
operation = getOperation(op); // 调用返回函数指针的函数
}
int calculate(int a, int b) {
if (operation) {
return (this->*operation)(a, b); // 调用成员函数指针
}
return 0;
}
};
int (Calculator::* Calculator::getOperation(char op))(int, int) {
switch (op) {
case '+':
return &Calculator::add;
case '-':
return &Calculator::subtract;
default:
return nullptr;
}
}
int main() {
Calculator calc;
calc.setOperation('+');
std::cout << "Addition: " << calc.calculate(5, 3) << std::endl;
calc.setOperation('-');
std::cout << "Subtraction: " << calc.calculate(5, 3) << std::endl;
calc.setOperation('*'); // Invalid operation
std::cout << "Invalid operation: " << calc.calculate(5, 3) << std::endl;
return 0;
}