Вперед объявить указатель метода - PullRequest
3 голосов
/ 30 декабря 2008

Я использую идиому 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 ]

6 голосов
/ 30 декабря 2008

Вы не можете переслать объявление функции-члена. Я думаю, причина в том, что когда вы вызываете функцию для указателя на B, компилятор должен передать указатель this этому методу. Но он еще не знает точную иерархию классов B. Поэтому возможные корректировки этого указателя (например, из-за того, что метод является виртуальным) не будут возможны в этот момент. Компилятор также не знает, какой видимость имеет этот метод. В конце концов, это может быть конфиденциально, и вам не разрешено звонить извне. Единственный способ объявить эту функцию-член - это определить класс, а затем объявить функцию в этом определении. Другой способ решить вашу проблему - объявить вашу свободную функцию:

class B;
void do_bar( B* b );

Затем определите do_bar в файле, в который вы можете безопасно включить определение класса B.

0 голосов
/ 30 декабря 2008

Не знаю, классы pimpl обычно тесно связаны с инкапсулирующим классом. Я думаю, что это немного запах, чтобы иметь это по-другому. Вот почему я обычно оставляю это как внутренний класс:

class A
{
public:
    ...
private:

    ...

    class A_impl;
    boost::scoped_ptr<A_impl> impl;
};
0 голосов
/ 30 декабря 2008

Он не может скомпилировать 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 void B::bar( void );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...