不允许成员函数的非指针类型定义
Non-pointer typedef of member functions not allowed?
得到这个问题的答案后,我发现有两种有效的方法来定义函数指针的类型。
typedef void (Function) ();
typedef void (*PFunction) ();
void foo () {}
Function * p = foo;
PFunction q = foo;
我现在更喜欢Function * p
而不是PFunction q
,但显然这不适用于指针到成员函数。考虑这个人为的例子。
#include <iostream>
struct Base {
typedef void (Base :: *Callback) ();
//^^^ remove this '*' and put it below (i.e. *cb)
Callback cb;
void go () {
(this->*cb) ();
}
virtual void x () = 0;
Base () {
cb = &Base::x;
}
};
struct D1 : public Base {
void x () {
std :: cout << "D1n";
}
};
struct D2 : public Base {
void x () {
std :: cout << "D2n";
}
};
int main () {
D1 d1;
D2 d2;
d1 .go ();
d2 .go ();
}
但是如果我将其更改为新的首选样式:typedef void (Base :: Callback) ()
和Callback * cb
,我在typedef
在成员'Callback'上附加限定'Base::'
演示错误。
为什么不允许?这只是一个疏忽还是会造成问题?
对于非成员函数,typedef void(Function)()
这样的类型有几种用途,但对于成员函数,唯一的应用是声明一个保存函数指针的变量。因此,除了风格偏好之外,没有严格需要允许这种语法,并且它已从标准中省略。
::
是作用域解析操作符,如果X
是类类型,则X::Y
语法保留用于static
成员访问。因此,X::*Z
是另一种用于定义指针到成员的语法。暂时忘记member-function,只考虑member-data,看看下面的代码:
struct X
{
int a;
};
int X::*pa = &X::a; //pointer-to-member
X x = {100}; //a = 100
cout << (x.*pa) << endl;
它定义了一个指向成员数据的指针,cout
用它来输出对象x
的a
的值,它输出:
100
Demo: http://www.ideone.com/De2H1
现在想想,如果X::pa
(而不是X::*pa
)被允许这样做,那么你就把上面的代码写成:
int X::pa = X::a; //not &X::a
看到这个语法,你如何判断X::a
是static
成员还是非静态成员?这就是为什么标准提出了指针到成员语法,并将其统一应用于非静态成员数据和非静态成员函数的原因之一。
事实上,不能写X::a
,你必须写&X::a
。语法X::a
会导致编译错误(参见此)。
现在将member-data的参数扩展为member-function。假设您有一个定义为:
的类型定义:typedef void fun();
那么你认为下面的代码是做什么的?
struct X
{
fun a;
};
它定义了fun
类型的成员a
(这是一个不带参数的函数,返回void),它等价于这个:
struct X
{
void a();
};
惊讶吗?读下去。
struct X
{
fun a; //equivalent to this: void a();
};
void X::a() //yes, you can do this!
{
cout << "haha" << endl;
}
我们可以使用完全相同的语法来引用a
,它现在是一个成员函数:
X x;
x.a(); //normal function call
void (X::*pa)() = &X::a; //pointer-to-member
(x.*pa)(); //using pointer-to-member
相似的是右边的语法:&X::a
。无论a
引用成员函数还是成员数据,语法都是一样的。
Demo: http://www.ideone.com/Y80Mf
结论:
我们知道,无论a
是成员数据还是成员函数,都不能在RHS上写X::a
。唯一允许的语法是&X::f
,这使得目标类型(在LHS上)必须是指针,这反过来又使得语法void (X::*pa)()
绝对必要和基本,因为它适合语言中的其他语法。
确切地说,在非成员指针的情况下,这两个类型定义是不相同的:
typedef void function();
typedef void (*fptr)();
第一个将function
定义为不接受参数并返回void
的函数,而第二个将ftpr
定义为指向不接受参数并返回void
的函数的指针。在许多上下文中,函数类型将隐式地转换为指针类型,这可能会引起混淆。但不是全部:
function f; // declares void f();
struct test {
function f; // declares void test::f()
};
void g( function f ); // declares g( void (*f)() ): function decays to pointer to function in declaration
g( f ); // calls g( &f ): function decays to pointer to function
void f() {} // definition of f
// function h = f; // error: cannot assign functions
function *h = f; // f decays to &f
让我们暂时跳过"function"部分。在c++中,我们有int
、int*
和int Foo::*
类型。这是一个普通整数,一个指向整型的指针,一个指向整型成员的指针。没有第四个类型的"整型成员"
同样适用于函数:没有"成员函数"类型,尽管有函数类型、函数指针类型和成员函数指针类型。
- C++中的双指针类型转换
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 将类指针类型转换为键时出错
- 错误:表达式必须具有算术、无作用域枚举或带有运算符重载的指针类型
- C++在一个映射中存储不同的指针类型(并处理销毁)
- 指针类型类成员的动态强制转换的恒定性是什么?
- 我正在尝试将表的地址传递给要在另一个函数中使用的指针,但得到不兼容的指针类型
- 在将派生类指针类型转换为派生类指针后,从基类指针调用派生类函数
- 如何使用静态多态性在 int 和指针类型之间进行转换?
- STL 函数和函数类型与函数指针类型
- 如何调用指针类型的方法(禁用多态性)?
- 为什么新表达式可以正确生成指针类型,即使它应该返回 void*?
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 是否允许调用方对我的 Builder 类使用任何指针类型(包括智能指针)?
- OPENCL 警告:不兼容的指针类型将'float __global[16]'传递给类型为 '__global float4 的参数 *
- 专门用于"direct"函数类型(与函数指针类型相对)
- 指向成员的指针类型和模板
- 返回对常量结构(指针类型)成员的引用:明显的左值到右值转换
- 在C++17中,为什么类模板和函数模板的指针类型推导明显不一致
- 为什么允许将整型、枚举和指向成员的指针类型reinterpret_cast到自身?