3

可能重复:
访问派生类中的受保护成员

如果我有一个抽象基类和一个从它派生的具体模板类,它有一个使用指向基类的指针的方法 - 派生类似乎不再将自己视为从它派生的:

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;
}

这与以下错误有关:

'virtual void AbstractBase::test()' 受保护

编译器没有错,肯定是protected- 但如果Derived< T >继承自AbstractBase,为什么会抱怨?

4

2 回答 2

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 );
于 2012-08-04T15:02:15.047 回答
1

这与模板无关,但通常与受保护的成员访问有关。请参阅最新公开可用的 C++标准草案的第 11.4 节受保护的成员访问 [class.protected]

当非静态数据成员或非静态成员函数是其命名类 (11.2) 的受保护成员 115 如前所述,授予对受保护成员的访问权限是因为引用出现在某个类 C 的朋友或成员中。如果访问要形成指向成员的指针 (5.3.1),则嵌套名称说明符应表示 C 或从 C 派生的类。所有其他访问都涉及(可能是隐式的)对象表达式(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)
}
于 2012-08-04T15:18:34.713 回答