前向声明方法指针

时间:2008-12-30 03:19:29

标签: c++ templates

我正在使用pimpl习语并想要引用前向声明类的一种方法。以下不是我正在做的事情,而是使用相同的概念。

template< typename Class, void (Class::*Method)(void) >
struct Call
{
   Call( Class* c )
    : m_c(c)
   { }

   void operator()( void )
   {
      (m_c->*Method)();
   }

   Class* m_c;
};

class A
{
public:
   void foo( void )
   {
      std::cout << "A::foo\n";
   }
};

// this works
void do_foo( A* a )
{
   Call<A,&A::foo> c(a);
   c();
}

class B;
// this doesn't compile
extern void B::bar( void );

// this is what i'd ultimately like to do
void do_bar( B* b )
{
   Call<B,&B::bar> c(b);
   c();
}

两个问题:

  • 可以这样做吗?
  • 为什么不能这样做?

3 个答案:

答案 0 :(得分:6)

您无法转发声明成员函数。我认为原因是,当你在指向B的指针上调用函数时,编译器必须将this指针传递给该方法。但它还不知道B的精确类层次结构。因此,该指针的可能调整(例如,由于该方法是虚拟的)将是不可能的。编译器也不知道该方法具有什么可见性。毕竟,它可能是私人的,你不能从外面打电话。声明该成员函数的唯一方法是定义该类,然后在该定义中声明该函数。解决问题的另一种方法是声明你的自由函数:

class B;
void do_bar( B* b );

然后在文件中定义do_bar,您可以在其中安全地包含B类的定义。

答案 1 :(得分:0)

它无法编译B :: bar(),因为B类未定义。但我认为你离开了太多问题。此时:

void do_bar( B* b )
{
   Call<B,&B::bar> c(b);
   c();
}

为什么你不能说出来?

void do_Bar(B* b) {
    b->bar();
}

也许如果你包含这个解释,那么回答你的问题会更容易。

第二,为什么在(如上所述)你想通过do_bar()调用它时需要这个?为什么不把do_bar作为extern?

extern void B::bar( void );

答案 2 :(得分:0)

我不知道,pimpl类通常与它们的封装类紧密相关。我认为以任何其他方式拥有它都有点气味。这就是为什么我通常把它留作内部阶级的原因:

class A
{
public:
    ...
private:

    ...

    class A_impl;
    boost::scoped_ptr<A_impl> impl;
};