首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >不允许成员函数的非指针类型定义?

不允许成员函数的非指针类型定义?
EN

Stack Overflow用户
提问于 2011-09-15 18:37:49
回答 3查看 2.1K关注 0票数 17

在得到this question的答案后,我发现有两种有效的方法来定义函数指针。

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,则会在typedef处得到一个编译器错误

回调成员‘

’的额外限定'Base::‘

Demo for error

为什么不允许这样做?这只是一个疏忽,还是会导致问题?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-09-15 19:00:31

对于非成员函数,像typedef void(Function)()这样的类型有多种用途,但对于成员函数,唯一的应用是声明一个保存函数指针的变量。因此,除了风格偏好之外,没有严格的需要允许这种语法,标准中也省略了它。

背景

::是一个作用域解析操作符,如果static是类类型,则语法X::Y保留用于X成员访问。因此,X::*Z是另一种用来定义成员指针的语法。

暂时忘掉成员函数,只需考虑一下成员数据,然后看看下面的代码:

struct X
{
   int a;
};

int X::*pa = &X::a; //pointer-to-member
X x = {100}; //a = 100
cout << (x.*pa) << endl;

它定义了一个指向成员数据的指针,cout使用它来打印object xa的值,并打印:

100

演示:http://www.ideone.com/De2H1

现在想一想,如果允许X::pa (而不是X::*pa)这样做,那么上面的代码是这样写的:

int X::pa = X::a; //not &X::a

看到这种语法,您如何判断X::astatic成员还是非静态成员?这就是为什么标准提出了指向成员的指针语法,并将其统一应用于非静态成员数据和非静态成员函数。

事实上,你不能写X::a,你必须写&X::a。语法X::a会导致编译错误(参见this)。

现在将这个成员数据的参数扩展到成员函数。假设你有一个定义为:

typedef void fun();

那么你认为下面的代码是做什么的呢?

struct X
{
   fun a;
};

它定义了fun类型的成员a (这是一个不带参数的函数,返回空值),等同于:

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引用成员函数还是成员数据,语法都是相同的。

演示:http://www.ideone.com/Y80Mf

结论:

因为我们知道,无论a是成员数据还是成员函数,我们都不能在RHS上编写X::a。唯一允许的语法是&X::f,这使得目标类型(在LHS上)也必须是指针,这反过来使得语法void (X::*pa)()是绝对必要的和基本的,因为它适合语言中的其他语法。

票数 10
EN

Stack Overflow用户

发布于 2011-09-15 19:08:10

准确地说,在非成员指针的情况下,两个类型定义函数是不同的:

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
票数 2
EN

Stack Overflow用户

发布于 2011-09-15 20:12:29

让我们暂时跳过“函数”部分。在C++中,我们有intint*int Foo::*类型。这是一个常规整数,指向整数的指针,以及指向整数成员的指针。没有第四种类型“整数成员”。

同样的道理也适用于函数:没有类型“成员函数”,即使有函数类型、函数指针类型和成员函数指针类型。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7429510

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档