Sign in to follow this  
Dave Eberly

C++ access modifiers and 'using' declarations

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
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
On topic again: my friend Google tells me ...

So you are indeed right that the additional scope should be necessary to let the compiler know that what you are calling is also depending on type T. But it is also correct that VS does not enforce this.

Edit (once again)
The link given above provides a technical explanation why you have to provide the scope. Now I think I remember I also stumbled across this problem when porting some Windows templates to Linux. But we humans forget so fast ... [grin]

Share this post


Link to post
Share on other sites
Quote:
Original post by WaterwalkerBut then, what would prevent me from inheriting another class from this guy and declare same nasty public using's for the whole interface?


Without guarantee that the standard says the same, but with VC the result is as expected. You simply can't access an inherited private member, so you can't "unprivate" it with 'using'. That would have been somewhat sabotaging the whole point of making it private (almost like casting away a 'const').

Share this post


Link to post
Share on other sites
Quote:
Original post by magic_man
I understand the idea behind the using statement yet not in the protected interface.


I place my data members in a final block in the C++ class interface (to avoid cluttering the first block which contains the services available to a class user), so the access modifier is typically private or protected. I put my 'using' statements in the last block just to put them *somewhere*, thinking that the access modifier has nothing to do with 'using'. I was not intentionally trying to modify the access rights for anything.

This is the point of original post. In my opinion, 'using' has to do with scoping identifiers. public/protected/private has to do with access rights. The fact that the two concepts can (apparently) interact is not intuitive.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave Eberly
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.

IIRC, it goes something like:

void foo(void) {
std::cout << "::foo()\n";
};

template <class T>
struct Bar : T {
Bar() {
foo(); // intends to call ::foo()
}
};

struct Baz {
void foo(void) {
std::cout << "Baz::foo()\n";
}
};

Bar<Baz> f;

With the gcc template implementation creating f results in "::foo()" getting printed. With MSVC you get "Baz::foo()". The standards committee decided that the global version of foo() should the one being called because that's the only one around when the template was defined. Introducing an additional foo() with the base class probably changes the meaning unintentionally. Also, if you follow the gcc method of doing things it's relatively easy to force the compiler to choose Baz::foo() if you really want it. It's harder to work the other direction.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave Eberly
@Waterwalker. You edited your post, but swiftcoder answered correctly.

This is unfair, he quoted my unqualified statements while I was already editing them away while he edited his own post [grin]

But like I said, Visual Studio does not enforce this rule so I had to google first to back up my uprising fears that yet again MS is not ANSI in this case. Next time I shall check first and post later.

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'.

*** Source Snippet Removed ***

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.


Maybe I'm misunderstanding the problem description, but I thought this was the entire point of the using keyword at class scope. For example, suppose you use inherit privately from some class. Now all of the base class's members appear to be private to clients of the derived class, regardless of their previous scope. So in effect they're private to the derived class. You then put a using statement at class scope under a public protection level and all the members then become public.

Am I missing something?

Secondly, regarding your other point about needing to use the this keyword to dereference the item if it DOESN'T have a using statement, that makes no sense. You're inheriting publicly and calling a base class function from a derived function. This is perfectly fine, so I'm not sure I understand why you would need to put a using in order to make it so that you did not have to write this->.

I don't have a copy of G++ but I tried it on Visual C++ 2008 and it works fine as you said. As in it compiles the code if I delete the 'using' line. But NOT working seems completely unbelievable to me, it's just basic inheritance and calling a base class function.

Maybe I'm just not aware of this rule since I use Visual C++ exclusively, but I would be very much interested if someone could point out in the Standard where it explains this because it is pretty surprising to me.

Share this post


Link to post
Share on other sites
Quote:
Original post by Trienco
Quote:
Original post by WaterwalkerBut then, what would prevent me from inheriting another class from this guy and declare same nasty public using's for the whole interface?
Without guarantee that the standard says the same, but with VC the result is as expected. You simply can't access an inherited private member, so you can't "unprivate" it with 'using'. That would have been somewhat sabotaging the whole point of making it private (almost like casting away a 'const').
That is as maybe, but g++ *does* allow me to promote protected functions from a base-class into public visibility - and that is an operation I am not entirely happy with.

The question, then, is what the standard says. Is GCC implementing the correct behaviour throughout, or should it only be possible to tighten the access controls (a la protected inheritance), rather than loosen them as well?

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave Eberly

This is the point of original post. In my opinion, 'using' has to do with scoping identifiers. public/protected/private has to do with access rights. The fact that the two concepts can (apparently) interact is not intuitive.

I am afraid you are incorrect. The using statement brings the function into the derived class and overrides the base class member function. The derived function access rights are as as if it was declare at the using statement and therefore is protected. Yet in the user class you try and call a function which you think is in the base, yet it is hidden and is in the derived instance in the protected interface.

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Quote:
Original post by Trienco
Quote:
Original post by WaterwalkerBut then, what would prevent me from inheriting another class from this guy and declare same nasty public using's for the whole interface?
Without guarantee that the standard says the same, but with VC the result is as expected. You simply can't access an inherited private member, so you can't "unprivate" it with 'using'. That would have been somewhat sabotaging the whole point of making it private (almost like casting away a 'const').
That is as maybe, but g++ *does* allow me to promote protected functions from a base-class into public visibility - and that is an operation I am not entirely happy with.

VS2008 does allow this as well. But I have to agree that I am not happy with that the same way I am not happy that it is actually possible to change access rights by deriving classes with either function overloading or using statements.

But we should not hijack this thread for discussing the general downsides of changing access rights. [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by Waterwalker
But I have to agree that I am not happy with that the same way I am not happy that it is actually possible to change access rights by deriving classes with either function overloading or using statements.



Again, this is the entire *point* of the using statement at class scope. It serves no other purpose except to change the access specifier of base class members in the derived class.

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
It serves no other purpose except to change the access specifier of base class members in the derived class.

Incorrect. using can move hidden declarations from a base class to the derived class.

struct Base {
void foo(int) {}
void foo(void) {}
};

struct Derived : Base {
void foo(int) {}
//using Base::foo;
};

int main(int, char **) {
Derived d;
d.foo();

return 0;
}

Without the using this will fail to compile because Derived::foo(int) hides both Base::foo(int) and Base::foo(void). This has nothing to do with access specifiers, but is a scope modifier.

Share this post


Link to post
Share on other sites
ok, fair enough. Didn't know about that. But in any case changing access is "the other" purpose of the using keyword then, since that's how you expose base class methods in private/protected inheritance.

Share this post


Link to post
Share on other sites
Thanks, SiCrane, for the example that shows why the rule exists. And thanks for all the input folks. Although it still remains to be seen what the standard actually says, it appears that 'using' is affected by the access modifier. I find this disconcerting, but if this is what the standard says, I'll have to modify where I place the 'using' statements in my class.

Share this post


Link to post
Share on other sites
FWIW I dug up my copy of the C++ Standard, and here's what we have.

7.3.3 The using declaration [namespace.udecl]
----1 A using-declaration introduces a name into the declarative region in which the using-declaration appears.
That name is a synonym for the name of some entity declared elsewhere.

----2 The member name specified in a using-declaration is declared in the declarative region in which the using-declaration
appears. [Note: only the specified name is so declared; specifying an enumeration name in a
using-declaration does not declare its enumerators in the using-declaration’s declarative region. ]

----3 Every using-declaration is a declaration and a member-declaration and so can be used in a class definition.

Example:

struct B
{
void f(char);
void g(char);
enum E { e };
union { int x; };
};

struct D : B
{
using B::f;
void f(int) { f(’c’); } // calls B::f(char)
void g(int) { g(’c’); } // recursively calls D::g(int)
};



Skipping forward a little from here, we have:

----15 The alias created by the using-declaration has the usual accessibility for a member-declaration.

Example:


class A
{
private:
void f(char);
public:
void f(int);
protected:
void g();
};

class B : public A
{
using A::f; // error: A::f(char) is inaccessible
public:
using A::g; // B::g is a public synonym for A::g
};



16 [Note: use of access-declarations (11.3) is deprecated; member using-declarations provide a better alternative.

Finally, referring to 11.3 to see what an "access declaration" is, it says:


11.3 Access declarations [class.access.dcl]

1---- The access of a member of a base class can be changed in the derived class by mentioning its qualified-id in the derived class declaration. Such mention is called an access declaration. The effect of an access declaration is defined to be equivalent to the declaration


using <qualified-id>;





So, it appears that protection level modification is a feature of the using keyword.

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoderThat is as maybe, but g++ *does* allow me to promote protected functions from a base-class into public visibility - and that is an operation I am not entirely happy with.


Why? This is just a much more convenient way than

public:
void f() { Base::f(); }
void f(float x) { return Base::f(x); }
int g() { return Base::g(); }



Just lacking a bit of fine control if you only want to make a few overloaded versions available. Generally 'using' won't let you do anything that you couldn't do without it. So technically you shouldn't be comfortable with being allowed to declare a non-virtual function of the same name in a derived class either.

Also note that my "doesn't work" comment was in regard to _private_ members of your base class. They are and remain inaccessible in your derived class and ergo can't be made less than private (and thanks to cache-hit we now know it's not just VC, it's the standard).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this