Topic: Should class-member using declarations behave differently from
Author: richard@ex-parrot.com (Richard Smith)
Date: Tue, 22 Jul 2003 18:47:23 +0000 (UTC) Raw View
Francis Glassborow wrote:
> However we could have provided an alternative form in which the using
> declaration still made the private member of the base class visible but
> kept it unusable by D.
I'm not sure I fully understand what you mean by "visible
but ... unusable by D". In the following code, do you want
the using declaration to inject two aliases into D, one for
each overload in B, with one having public accesibility and
one having no accesibility?
class B {
private: void x(int);
public: void x();
};
class D : public B {
public: using B::x;
};
Imagine for a moment that there is an additional access-
specifier, "inaccessible", meaning inaccessible even from
within the class. This would make the above definition of D
equivalent to
class D : public B {
inaccessible: void x(int); // unimplemented
public: void x() { return B::x(); }
};
So what if the user wants to add another overload of x to
the derived class:
class D : public B {
public:
using B::x;
void x(int);
};
This would then be an redefinition of x(int), and so the
presence (if not semnatics) of B::x(int) suddenly become
part of the exposed interface of B. (They have to be
documented so users can avoid this type of problem.)
I'm not sure that allowing this extention is really
particularlly useful. It seems to me to just be moving the
problem.
> What we have currently is that any name that is
> overloaded with at least one private declaration cannot be handled via a
> using declaration.
How common do you think this is? I can't say I've ever been
tempted to do this. Isn't it better to just say "don't do
it".
> There is also the issue as to whether we should have had class scope
> using declarations apply to data (they serve no useful purpose because
> IIRC a name used for data cannot also be overloaded as a name for a
> function.
They can be used to break the accessibility specified in the
base class, e.g.
class B {
protected: int x;
};
class D : public B {
public: using B::x;
};
Not a particularly good thing to be encouraging, but a use
none the less.
> I think that we did not think carefully enough about the issues when we
> introduced class scope using declarations.
Agreed. Another thing with class scope using declarations
that I've never properly understood is why there is an
ambiguity in the following code copied from 7.3.3/15:
struct A { int x(); };
struct B : A {};
struct C : A {
using A::x;
int x(int);
};
struct D : B, C {
using C::x;
int x(double);
};
int (D* d) {
return d->x(); // Ambiguous
}
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: richard@ex-parrot.com (Richard Smith)
Date: Wed, 23 Jul 2003 15:09:09 +0000 (UTC) Raw View
Francis Glassborow wrote:
> Richard Smith <richard@ex-parrot.com> writes:
>
> >So what if the user wants to add another overload of x to
> >the derived class:
> >
> > class D : public B {
> > public:
> > using B::x;
> > void x(int);
> > };
[...]
> Check how overriders currently work in the presence of a using
> declaration. I think you will find that they are fine.
OK, you're right. I'd forgetten that.
> >I'm not sure that allowing this extention is really
> >particularlly useful. It seems to me to just be moving the
> >problem.
>
> Unfortunately we cannot really allow this extension because the damage
> is already done with the changed access rules for public and protected
> members of an overload set.
Are you of the opinion that using declarations should never
be used to increase the accesibility of a name then? Whilst
I admit that
class B {
protected: void x();
};
class D : public B {
public: using B::x;
};
is often symptomatic of bad design, I'm not at all
convinced that
class B {
public: void x();
};
class D : private B {
public: using B::x;
};
is a problem. Both of these use a class scope using
declaration to increase accessibility. I would be happy to
see the former made illegal (though I appreciate that it
would break too much existing code for this to be possible);
I am not happy about the latter being illegal.
> >> What we have currently is that any name that is
> >> overloaded with at least one private declaration cannot be handled via a
> >> using declaration.
> >
> >How common do you think this is? I can't say I've ever been
> >tempted to do this. Isn't it better to just say "don't do
> >it".
>
> It means that we just about cannot inject ctors into a derived class by
> extending the using declaration rules and that is something many people
> definitely do want to do.
I don't think it prevents this at all. A constructor using
declaration is currently never legal, so it's semantics are
currently undefined. A future standard could perfectly
happily make the semantics of constructor using declarations
different from other member using declarations.
Secondly, I'm not convinced that using declarations are the
best way to do this, as they (presumably) would prevent
non-default initialisation of members of the derived class.
(For that matter, how would you have them initialise
integers? Zero-initialise them? Or leave them undefined?
The latter would seem to be the logical thing, but probably
less sensible than the former.) I think that a mechanism
such as described in 13.13 of "C++ Templates: The Complete
Guide" by Vandevoorde & Josuttis would provide a much more
complete solution:
class D : public B
{
public:
template <... List>
D( List const& list )
: B(list), x(42)
{}
private:
int x;
};
> > class B {
> > protected: int x;
> > };
> >
> > class D : public B {
> > public: using B::x;
> > };
> >
> >Not a particularly good thing to be encouraging, but a use
> >none the less.
>
> Now you are supporting poor coding as a justification.
I'm using poor existing coding as a justification for
keeping what we've got. Not quite the same thing ;-) If we
we're able to start a fresh with member using declarations,
I would probably agree with you.
Of course, perhaps we could salvage something by introducing
a more restricted form of using declaration
class B {
public: void x(void);
protected: void x(int);
};
class D1 : public B {
// Inject a public alias to void x(void);
public: using public B::x;
// Inject a private alias to void x(int);
private: using protected B::x;
};
class D2 : private B {
// Inject a public alias to void x(void);
public: using public B::x;
// Note that even though B::x(void) would otherwise be
// private within the context of D2 (due to private
// inheritance), it is still refered to with a using
// public declaration as it is public in the context of
// B.
};
class D3 : public B {
public: using private B::x;
// Error! Cannot use this sort of using declaration to
// increase accesibility.
};
Of course, I can't see this happening as we already have one
legacy syntax for changing function accessibilty (namely
access declarations). I don't imagine a second one will be
popular.
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: richard@ex-parrot.com (Richard Smith)
Date: Mon, 21 Jul 2003 15:07:32 +0000 (UTC) Raw View
Francis Glassborow wrote:
> No you are perfectly right however I am not convinced that it should be.
But it breaks encapsulation by allowing members of one class
access to the private members of another.
class B {
private: int x;
};
class D : public B {
void f() { cout << x << endl; }
};
This is an error: x is a private member of B so can't be
accessed by D. Now consider add a using declaration to D:
class D : public B {
private: using B::x;
void f() { cout << x << endl; }
};
Now the name x is a private member of D, which can be
accessed within D.
By allowing this you allow derived classes to access *any*
data member of a base class. I think this would be a very
bad idea indeed.
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]