Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template derived from interface - polymorphism stopped working? [duplicate]

Possible Duplicate:
Accessing protected members in a derived class

If I have an abstract base class and a concrete templated class that derives from it, which has a method that uses a pointer to the base class - it seems that the derived class stops seeing itself as derived from it:

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

This errors with:

'virtual void AbstractBase::test()' is protected

The compiler's not wrong, it's definitely protected - but if Derived< T > inherits from AbstractBase, why is it complaining?

like image 574
cmannett85 Avatar asked Sep 11 '26 20:09

cmannett85


2 Answers

The reason it isn't allowed is because AbstractBase as a type declares test to be protected. This makes it private to all unless the current class is a direct descendant of AbstractBase. Even so, that class can only access the member though an object of the same class, not a different descendant, and not directly from AbstractBase itself.

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() {}
};

You can, as demonstrated above, just allow it for pointers of the same type. Alternatively, you can create a proxy base class for Derived to implement your virtual method to call test. This will allow access from different Derived types.

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

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

And can be accessed this way:

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

   b.call( &a );
   c.call( &a );
like image 162
jxh Avatar answered Sep 13 '26 09:09

jxh


This is not related to templates, but to protected member access in general. See section 11.4 Protected member access [class.protected] of the latest publicly available draft C++ Standard

An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class (11.2) 115 As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denote C or a class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C.

[Example:

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)
}
like image 42
TemplateRex Avatar answered Sep 13 '26 08:09

TemplateRex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!