Good or bad shading depends on the order in which you entered the conflicting names.
Suppose you have a class library, and one of the classes:
struct Base { int a; };
Later, client A, which uses your class library, writes the following:
class DerivedA : public Base { private: int a; };
In this case, shading is possible unintentionally. The client is accidentally obscured by Base::a
.
However, suppose you also have client B that writes this:
class DerivedB : public Base { private: int b; };
So far so good. Now you create your library to use Base
objects, and client B, which uses your library, creates a body of code that uses Base
and DerivedB
.
In a few weeks you will realize that in order to get a new function, you need to add a new element to Base
.
struct Base { int a; int b;
Does this create a problem with your library? Does this create a problem with client B?
No, this does not create any problems.
All your code that uses Base
will continue to use Base
, and it can use member b
to get the fantastic new function b
. Even if a DerivedB
object DerivedB
passed to a function that expects Base
, Derived
hiding b
does not affect Base
. Your function using Base
can say b
and gain access to the Base
member variable.
Meanwhile, all client B code that uses DerivedB
will continue to use DerivedB
, and when that code says b
, it gets DerivedB::b
, as before. Few, shading saved the day!
(Of course, if client B wants to start using the new function b
, then client B needs to do extra work to resolve the conflict. But the important thing is that the shading did not create any new problems in the existing code.)
At the end of the day, good or bad shading depends on the order in which you entered the conflicting names. This is not what the compiler understands.