2008-12-30 50 views
3

我使用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(); 
} 

兩個問題:

  • 可以這樣做?
  • 爲什麼不能做到?

回答

6

你不能轉發聲明一個成員函數。我認爲原因是,當你在一個指向B的指針上調用該函數時,編譯器必須將該指針傳遞給該方法。但它並不知道B的確切類層次結構。該指針,從而可能的調整(由於該方法的虛擬,例如)在該點處將是不可能的。編譯器也不知道該方法的可見性。畢竟,它可能是私人和你不能從外部調用它。聲明該成員函數的唯一方法是定義該類,然後在該定義中聲明該函數。爲您解決問題的另一種方法是聲明你的自由函數:

class B; 
void do_bar(B* b); 

在一個文件然後定義do_bar中,你可以放心地包括B類的定義

0

(),因爲B類未定義它不能編譯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); 
0

我不知道,pimpl類通常緊緊地綁定到它們的封裝類。我認爲有任何其他方式有點味道。這就是爲什麼我通常把它作爲內部類的原因:

class A 
{ 
public: 
    ... 
private: 

    ... 

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