Jump to content
  • Advertisement
Sign in to follow this  
Dave Eberly

C++ access modifiers and 'using' declarations

This topic is 3229 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have an unexpected compiler error in the following code. It appears as if the access modifier before a 'using' declaration changes the access rights of a base-class function from 'public' to 'protected'.
//----------------------------------------------------------------------------
template <typename T>
class Base
{
public:
    void MyBaseFunction () {}
};
//----------------------------------------------------------------------------
template <typename T>
class Derived : public Base<T>
{
public:
    void MyDerivedFunction ()
    {
        // Without 'using', must use this->MyBaseFunction().  Well, at least
        // when using g++ (Microsoft compilers do not enforce this rule).
        MyBaseFunction();
    }
protected:  // ACCESS_MODIFIER
    using Base<T>::MyBaseFunction;
};
//----------------------------------------------------------------------------
template <typename T>
class User
{
public:
    User (Derived<T> derived)
    {
        mDerived = derived;

        // When 'protected' is in the line tagged ACCESS_MODIFIER, compiler
        // error is generated for the following line of code:  Cannot access
        // protected member MyBaseFunction.  When 'public' is in the line
        // tagged ACCESS_MODIFIER, code compiles.
        mDerived.MyBaseFunction();
    }
private:
    Derived<T> mDerived;
};
//----------------------------------------------------------------------------
int main ()
{
    Derived<int> derived;
    User<int> object(derived);
    return 0;
}
//----------------------------------------------------------------------------

Is this behavior dictated by the ANSI C++ rules? I would find it annoying that in addition to specifying 'using' statements in a derived template class in order to use base-class members without having to scope with 'this->mBaseClassMember', I would also have to place the 'using' statements in blocks with the proper access modifier. Speaking of that annoyance, someone once explained to me why 'using' is now needed in this context, but I do not recall the explanation. Anyone care to enlighten me about this? Thanks.

Share this post


Link to post
Share on other sites
Advertisement
I do not fully understand what you are trying to achieve with the using statement in protected. As you already pointed out you can use this->MyBaseFunction as it is type dependant or Base<T>::MyBaseFunction.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave Eberly
I have an unexpected compiler error in the following code. It appears as if
the access modifier before a 'using' declaration changes the access rights
of a base-class function from 'public' to 'protected'.
As an interesting side effect, g++ also allows me to pull a *protected* member of the base class into public visibility.

That surely qualifies as a bug/issue, right?
Quote:
Original post by Waterwalker
There is no need to include this "using" line. Since Derived inherits Base you can call MyBaseFunction without problems. So just remove this line.
Try it for yourself (under gcc) and see. Although you would generally be correct, the use of templated base-classes causes this issue.

Share this post


Link to post
Share on other sites
Quote:
Original post by magic_man
I do not fully understand what you are trying to achieve with the using statement in protected. As you already pointed out you can use this->MyBaseFunction as it is type dependant or Base<T>::MyBaseFunction.


In my derived template class, if I have to prefix every access to a base class member/function with "this->", that makes for very unreadable code, defeating one of the advantages of C++ in the first place.

This same requirement does not show up in non-templated classes. My use of "using" is to satisfy g++ on Linux and Macintosh where the g++ compilers are implementing ANSI rules. Microsoft has not implemented this rule yet.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave Eberly
Is this behavior dictated by the ANSI C++ rules? I would find it annoying
that in addition to specifying 'using' statements in a derived template
class in order to use base-class members without having to scope with
'this->mBaseClassMember', I would also have to place the 'using' statements
in blocks with the proper access modifier.


As far as I understand it, anything else would make it impossible to use 'using' in other common ways. For example making inherited protected functions public (questionable use, but at least avoids writing annoying forwarding functions) or making public/protected functions private (probably more useful to further restrict the interface).

Share this post


Link to post
Share on other sites
Are you sure you have to use the "using" statement to avoid the "this->" scoping? VS2008 Express compiles fine without the "using" statement; although I admit that MS was not known as strict ANSI enforcer in the past.

Anyway, the change in accessor rights would be what I expected from C++. Overriding a virtual function with different access rights is by ANSI standard allowed (which I finc a pity, btw) so I would expect the same from a using statement that has been declared protected.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave Eberly
In my derived template class, if I have to prefix every access to a base class member/function with "this->", that makes for very unreadable code, defeating one of the advantages of C++ in the first place.

I would have to disagree with you here, it makes perfect sense and it totally readable IMHO.
Quote:

This same requirement does not show up in non-templated classes. My use of "using" is to satisfy g++ on Linux and Macintosh where the g++ compilers are implementing ANSI rules. Microsoft has not implemented this rule yet.

I understand the idea behind the using statement yet not in the protected interface.

Quote:
Waterwalker
Are you sure you have to use the "using" statement to avoid the "this->" scoping?
Yes it is required the other method is in my first post.

Share this post


Link to post
Share on other sites
Quote:
Original post by Trienco
... or making public/protected functions private (probably more useful to further restrict the interface).

Surely one interesting approach to close a class hierarchy in C++ I have never thought of. But then, what would prevent me from inheriting another class from this guy and declare same nasty public using's for the whole interface?

Sorry for being off topic.

Share this post


Link to post
Share on other sites
@Waterwalker. You edited your post, but swiftcoder answered correctly. This is a scope issue that changed some years ago. If mMember is a public/protected base-template-class member, and if a derived-template class references mMember, a g++ compiler will complain that the identifier is undefined. mMember in the derived class *does not* resolve to this->mMember (as it used to years ago). Instead, the compiler checks for an identifier mMember declared *outside* the scope of the class. This is why you either have to (1) explicitly scope it yourself with this->mMember or (2) add a 'using' statement to avoid having to explicity scope it.

In my original post, I mentioned that someone had explained the rationale to me, but I have forgotten it. I find it completely uninituitive that a compiler would check for mMember in a global scope when it is a base-class member. No doubt there is some "edge case" that led to this rule; I just cannot recall it.

For developers targeting only Windows with the Microsoft compiler, you do not have to deal with this because Microsoft has not implemented the rule. When you support multiple platforms (as my code does), this becomes a PITA for portability. I develop on Windows, then test on Linux/Macintosh, and then I spend time adding all the 'using' statements I forgot (because the Microsoft compiler did not bother to generate the error).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!