2012-08-04 57 views
3

可能重複:
Accessing protected members in a derived class來自接口的模板 - 多態性停止工作?

如果我有一個抽象基類和從它派生的混凝土模板類,它具有一個使用指針的基類的方法 - 似乎派生類停止將其本身視爲派生自它:

class AbstractBase 
{ 
protected: 
    virtual void test() = 0; 
}; 

template < class T > 
class Derived : public AbstractBase 
{ 
public: 
    virtual void call(AbstractBase* d) { d->test(); } // Error! 
protected: 
    virtual void test() {} 
}; 

int main() 
{ 
    Derived<int> a; 
    Derived<int> b; 

    b.call(&a); 

    return EXIT_SUCCESS; 
} 

此錯誤與:

'虛擬無效AbstractBase ::測試()' 被保護

編譯器的沒有錯,這是絕對protected - 但如果從AbstractBaseDerived<T>繼承,它爲什麼抱怨?

+3

這是不相關的模板。使派生一個非模板類,你會得到相同的錯誤。 – Mat 2012-08-04 14:45:37

+0

+1你是對的,但在我的無知中,當我遇到問題時,我搜索了這個問題,所以我會把問題留給其他做同樣事情的人。 – cmannett85 2012-08-04 15:24:27

回答

3

不允許的原因是因爲AbstractBase作爲類型聲明test被保護。除非當前班級是AbstractBase的直系後裔,否則這將使其對所有人都是私人的。即使如此,該類只能通過同一類的對象訪問成員,而不是其他類的對象,而不是直接從AbstractBase本身訪問成員。

template < class T > 
class Derived : public AbstractBase 
{ 
public: 
    virtual void call(Derived * d) { 
     d->test(); // ok, d has same type as this 
     AbstractBase *b = this; 
     b->test(); // not ok 
    } 
protected: 
    virtual void test() {} 
}; 

如上所示,您可以將其指定爲相同類型的指針。或者,您可以爲Derived創建代理基類,以實施您的virtual方法,以調用test。這將允許從不同的Derived類型訪問。

class DerivedBase : public virtual AbstractBase 
{ 
public: 
    virtual void call(DerivedBase * d) { d->test(); } 
}; 

template < class T > 
class Derived : public DerivedBase 
{ 
protected: 
    virtual void test() {} 
}; 

而且可以訪問這種方式:

Derived<int> a; 
    Derived<int> b; 
    Derived<float> c; 

    b.call(&a); 
    c.call(&a); 
+0

由於結構性原因,我無法在我的「真實」代碼上執行第一個選項,但它很適合注意。至於第二,你能解釋爲什麼這有效嗎?在我看來,這只是另一層抽象。 – cmannett85 2012-08-04 15:12:20

+0

忘掉模板。它不會工作。你正在工作,我正在改變。 – jxh 2012-08-04 15:18:43

+0

@ cbamber85:抽象層工作的原因是它成爲一個通用的基類,它爲'call'提供一個公共接口,用於調用受保護的'test'方法。然後,所有的「派生」代替繼承自「DerivedBase」。 – jxh 2012-08-04 15:23:34

1

這是不相關的模板,但受保護的成員訪問一般。見部11.4受保護的成員接入[class.protected]最新公開可用的C++草案Standard

超出在第11 前面描述的附加的訪問檢查時應用非靜態數據成員或非 - 如果前面描述的是 ,則授予訪問受保護成員的權限,因爲參考 發生在朋友或某個類C的成員中。如果訪問要形成 指向成員(5.3.1)的指針,嵌套名稱指定器應表示C 或類派生d。所有其他訪問涉及(可能爲 隱式)對象表達式(5.2.5)。在這種情況下,類 對象表達的應是C或從C

派生的類[例如:

class B { 
protected: 
    int i; 
    static int j; 
}; 

class D1 : public B { 
}; 

class D2 : public B { 
    friend void fr(B*,D1*,D2*); 
    void mem(B*,D1*); 
}; 

void fr(B* pb, D1* p1, D2* p2) { 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    p2->i = 3; // OK (access through a D2) 
    p2->B::i = 4; // OK (access through a D2, even though 
       // naming class is B) 
    int B::* pmi_B = &B::i; // ill-formed 
    int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*) 
    B::j = 5; // OK (because refers to static member) 
    D2::j = 6; // OK (because refers to static member) 
} 
+0

+1非常簡潔的答案,謝謝。 – cmannett85 2012-08-04 15:28:19