[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::c_plus_plus

Title:C++
Notice:Read 1.* and use keywords (e.g. SHOW KEY/FULL KIT_CXX_VAX_VMS)
Moderator:DECCXX::AMARTIN
Created:Fri Nov 06 1987
Last Modified:Thu Jun 05 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3604
Total number of notes:18242

3514.0. "Calling protected member functions from withing a class hierarchy: this vs object" by TLE::LUCIA (http://asaab.zko.dec.com/~lucia/biography.html) Tue Mar 25 1997 19:49

Can someone please straighten out my understanding of protected member
functions.  I *thought* as long as I was in the hierarchy, I could call a
protect member function, regardless of whether it was this->member() or
object.member().  Am I wrong?  The compiler would seem to think so.  Several
other knowledgeable folks inquired as to the possibility of a compiler bug, but
it gives the same message on Sun and on VC++.

Thanks,
Tim


class Foo {
protected:
    virtual int bar(void) const {return 1;}
};

class Foo1 : public Foo {
protected:
    virtual int bar(void) const;
};

int Foo1::bar(void) const
{
    const Foo X;
    if (1) {
	return Foo::bar();
    }
    else {
	return X.bar();
    }
}

% cxx -g test.C
cxx: Error: test.C, line 18: In this statement, "Foo::bar" is not accessible.
	return X.bar();
---------------^
T.RTitleUserPersonal
Name
DateLines
3514.1protected member access rulesDECC::J_WARDTue Mar 25 1997 20:0213
p. 568 of Stroustrup's "C++ Programming Language, second edition":

A friend or a member function of a derived class can access a protected
nonstatic member of one of its base classes only through a pointer to,
reference to, or object of the derived class (or any class derived
from that class).

In your example,

Foo::bar() is using the implicit this pointer (a pointer of the derived class)
X.bar() is using a Foo object, which is not of the derived class

3514.2Be friends with your descendantsDECCXX::RMEYERSRandy MeyersWed Mar 26 1997 21:3131
Re: .0

If you really want your derived classes to be able to access the protected
(and private) members of the base class through a pointer to the base class,
you can make the derived class a friend:

class Foo1;		// New line -- Forward reference to Foo1

class Foo {
    friend class Foo1;	// New line -- Make derived class a friend
protected:
    virtual int bar(void) const {return 1;}
};

class Foo1 : public Foo {
protected:
    virtual int bar(void) const;
};

int Foo1::bar(void) const
{
    const Foo X;
    if (1) {
        return Foo::bar();
    }
    else {
        return X.bar();
    }
}

This might not be the best idea in the world, however.
3514.3Okay, then why is this allowed?TLE::LUCIAhttp://asaab.zko.dec.com/~lucia/biography.htmlTue Apr 01 1997 17:0841
I went the 'friend' route for a while.  It bothered me so much, I came up with
the following.  It kind of defeats the whole rule in the first place, although
it is a maintenance headache.  Why is the following allowed if the former is not?

#include <iostream.h>

class Foo {
protected:
  virtual int joe(void) const { cout << "Foo::joe(void)" << endl; return 1;}
  virtual int joe(Foo* f) const { cout << "Foo::joe(Foo*)" << endl; return
f->joe();}

};

class Foo1 : public Foo {
protected:
    virtual int joe(void) const;
    virtual int joe(Foo* f) const { cout << "Foo1::joe(Foo*)" << endl; return
Foo::joe(f);}
public:
    int pubmem(void) const { return joe(); }
};

int Foo1::joe(void) const
{
    cout << "Foo1::joe(void)" << endl;
    Foo X;
    if (1) {
        return Foo::joe();
    }
    else {
        return joe(&X);
    }
}

int main()
{
    Foo1 aFoo1;
    cout << "aFoo1.pubmem() = " << aFoo1.pubmem() << endl;
    return 0;
}
3514.4SPECXN::DERAMODan D'EramoTue Apr 01 1997 17:4653
	All of the calls to joe in any of the derived class (Foo1)
        member functions either call the dervied class's joe or call
        the base class's (Foo's) joe via the "this" pointer to a
        derived class object.  So they are all legal.
        
        Dan
        
        
class Foo1 : public Foo {
protected:
    virtual int joe(void) const;
    virtual int joe(Foo* f) const { cout << "Foo1::joe(Foo*)" << endl; return
Foo::joe(f);}

        // no reason for the above to fail; Foo::joe(Foo *) is
        // accessed through the derived class pointer "this"
        
public:
    int pubmem(void) const { return joe(); }

        // no reason for the above to fail, Foo1 can access Foo1::joe(void)
        
};

int Foo1::joe(void) const
{
    cout << "Foo1::joe(void)" << endl;
    Foo X;
    if (1) {
        return Foo::joe();

        // no reason for the above to fail; Foo::joe(Foo *) is
        // accessed through the derived class pointer "this"
        
    }
    else {
        return joe(&X);

        // no reason for the above to fail, Foo1 can access Foo1::joe(Foo *)
        
    }
    // these would be illegal though
    // X.joe(); // illegal -- Foo::joe(void) accessed not through a Foo1
    // Foo *p = &X;
    // p->joe(); // illegal -- Foo::joe(void) accessed not through a Foo1
}

int main()
{
    Foo1 aFoo1;
    cout << "aFoo1.pubmem() = " << aFoo1.pubmem() << endl;
    return 0;
}   
3514.5TLE::LUCIAhttp://asaab.zko.dec.com/~lucia/biography.htmlTue Apr 01 1997 20:433
I understand why this particular example works.  What I don't understand is the
reasoning behind the first one not working.  I.e., "Bjarne, what were you
thinking?"
3514.6SPECXN::DERAMODan D'EramoTue Apr 01 1997 21:4831
        Without the restriction protected access would be meaningless. 
        Anyone would be able to call protected non-static member
        functions...
        
        
        
        #include "ClassX.h"
        
        class Hack : public ClassX {
        public:
            void bypass(ClassX &x) { x.protected_member_function(); }
        };
        
        int main()
        {
            ClassX x;
            // x.protected_member_function(); // illegal
            Hack h;
            h.bypass(x); // heh heh heh ... oops, Bjarne says no
        
            return 0;
        }
        
        
        
        The restriction means that a legitimate derived class can
        still use the base class's protected member functions on its
        own instances.  It just can't be used to bypass access
        checking on other objects not of the derived class.
        
        Dan