不允许成员函数的非指针 typedef?
在得到这个问题的答案后,我发现有两个typedef 函数指针的有效方法。
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 << "D1\n";
}
};
struct D2 : public Base {
void x () {
std :: cout << "D2\n";
}
};
int main () {
D1 d1;
D2 d2;
d1 .go ();
d2 .go ();
}
但是,如果我将其更改为新的首选样式: typedef void (Base :: Callback) ()
和 Callback * cb
,我会在 处收到编译器错误代码>类型定义
成员“Callback”上的额外限定“Base::”
错误演示。
为什么这是不允许的?这只是一个疏忽还是会导致问题?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于非成员函数,诸如 typedef void(Function)() 之类的类型有多种用途,但对于成员函数,唯一的应用是声明一个保存函数指针的变量。因此,除了风格偏好之外,没有严格需要允许这种语法,并且它已从标准中省略。
背景
::
是范围解析运算符,语法X::Y
保留用于static
成员访问,如果X< /code> 是一个类类型。因此,
X::*Z
是另一种为定义指向成员的指针而发明的语法。暂时忘记成员函数,只考虑成员数据,看看这段代码:
它定义了指向成员数据的指针 >,并且
cout
使用它来打印对象x
的a
的值,并打印:Demo : http://www.ideone.com/De2H1
现在想想,如果
X::pa
(而不是X::*pa) 被允许这样做,那么您将上面的内容编写为:
看到这个语法,您如何判断
X::a
是否是static
成员或非静态成员?这就是标准提出指向成员的指针语法的原因之一,并将其统一应用于非静态成员数据以及非静态成员函数。。事实上,您不能编写
X::a
,您必须编写&X::a
。语法X::a
会导致编译错误(请参阅此)。现在将成员数据的这个参数扩展到成员函数。假设您的 typedef 定义为:
那么您认为以下代码会做什么?
好吧,它定义了
fun
类型的成员a
(这是不带参数、返回 void 的函数),并且等价于:惊讶吗?请继续阅读。
我们可以使用完全相同的语法来引用现在是成员函数的
a
:相似之处在于右侧的语法:
&X::a
。无论a
是指成员函数还是成员数据,语法都是相同的。演示: http://www.ideone.com/Y80Mf
结论:
作为我们知道,无论
a
是成员数据还是成员函数,我们都不能在RHS上编写X::a
。唯一允许的语法是&X::f
,这使得目标类型(LHS 上)也必须是 pointer ,这反过来又使得语法 void (X::*pa)() 绝对必要且基本,因为它与该语言中的其他语法相匹配。For non-member functions, a type such as
typedef void(Function)()
has several uses, but for member functions the only application is to declare a variable which holds a function pointer. Hence, other than a stylistic preference, there's no strict need to allow this syntax and it has been omitted from the standard.Background
The
::
is a scope resolution operator, and the syntaxX::Y
is reserved forstatic
member access ifX
is a class type. SoX::*Z
was another syntax invented to define pointer-to-member.Forget member-function for a while, just think about member-data, and see this code:
It defines a pointer-to-member-data, and the
cout
uses it to print the value ofa
of objectx
, and it prints:Demo : http://www.ideone.com/De2H1
Now think, if
X::pa
(as opposed toX::*pa
) were allowed to do that, then you've written the above as:Seeing this syntax, how would you tell if
X::a
is astatic
member or non-static member? That is one reason why the Standard came up with pointer-to-member syntax, and uniformly applies it to non-static member-data as well as non-static member-function.In fact, you cannot write
X::a
, you've to write&X::a
. The syntaxX::a
would result in compilation error (see this).Now extend this argument of member-data to member-function. Suppose you've a typedef defined as:
then what do you think the following code does?
Well, it defines member
a
of typefun
(which is function taking no argument, and returning void), and is equivalent to this:Surprised? Read on.
We can use exactly the same syntax to refer to
a
which is now a member-function:The similarity is the synatax on the right hand side :
&X::a
. Whethera
refers to a member-function or member-data, the syntax is same.Demo : http://www.ideone.com/Y80Mf
Conclusion:
As we know that we cannot write
X::a
on the RHS, no matter ifa
is a member-data or member-function. The only syntax which is allowed is&X::f
which makes it necessary that the target type (on LHS) must be pointer as well, which in turn makes the syntaxvoid (X::*pa)()
absolutely necessary and fundamental, as it fits in with other syntax in the language.准确地说,在非成员指针的情况下,两个 typedef 是不同的:
第一个将
function
定义为不带参数并返回void
的函数,而第二个将ftpr
定义为指向不带参数并返回void
的函数的指针。由于函数类型在许多上下文中将隐式转换为指针类型,因此可能会出现混乱。但并非全部:To be precise the two typedef's in the case of the non-member pointers are not the same:
The first defines
function
as a function taking no arguments and returningvoid
, while the second definesftpr
as a pointer to function taking no arguments and returningvoid
. The confusion probably arises as the function type will be implicitly converted to a pointer type in many contexts. But not all:让我们暂时跳过“函数”部分。在 C++ 中,我们有
int
、int*
和int Foo::*
类型。这是一个常规整数、指向整数的指针和指向整数成员的指针。不存在第四种“整数成员”。这同样适用于函数:尽管有函数类型、函数指针类型和成员函数指针类型,但只是没有“成员函数”类型。
Let's skip the "function" part for a second. In C++, we have the
int
, theint*
and theint Foo::*
types. That's a regular integer, pointer to integer, and a pointer to an integer member. There is no fourth type "integer member".Exactly the same applies to functions: there's just no type "member function", even though there are function types, function pointer types, and member function pointer types.