Re: Covariant returns, inheritance, and named parameter idiom?!
Dave Shawley ha scritto:
struct Base {
struct options {
virtual ~options() {}
virtual options& setBaseOption (int x) {
m_x = x;
return *this; }
int m_x;
};
Base (options& opts) : m_baseOptions(opts) {}
virtual ~Base() {}
options m_baseOptions;
};
struct Derived : public Base {
struct options : Base::options {
virtual ~options() {}
virtual options& setDerivedOption (int y) {
m_y = y;
return *this; }
int m_y;
};
Derived (options& opts) : Base(opts), m_derivedOptions(opts) {}
virtual ~Derived() {}
options m_derivedOptions;
};
int
main()
{
Derived object(Derived::options()
.setBaseOption(1)
.setDerivedOption(2));
return 0;
}
Now this doesn't work with g++ 4.0.1:
covariant.cpp: In function 'int main()':
covariant.cpp:32: error: 'struct Base::options' has no member named
'setDerivedOption'
I think that it should! I did a bunch of other variations using
pointers instead of references and stuff like that without any better
results. Is this a case of g++ not implementing covariant returns
properly? I've showed that at runtime this would work - inside of
setBaseOption, typeid(this) does return the expected type (Derived).
However, it looks like the compiler is statically typing the return
value of setBaseOption to Base&. Is this correct?
Yes, it's correct: it shouldn't work.
Do I have to explicitly override setBaseOption inside of
Derived::options to make this work?
Yes.
This does the trick for g++, but is
it required by the ANSI/ISO standard? For example, adding the following
member to Derived::options makes things work, but I really don't want
to do this.
virtual options& setBaseOption (int x) {
Base::options::setBaseOption(x);
return *this;
}
It is going to make maintenance of the class hierarchy a nightmare
since it requires you to modify every derived class whenever you modify
a base class :(
Covariance was not meant for this. You are just blaming a tool because
it doesn't do something that it wasn't designed for but you desperately
need.
There's a very good reason for not having covariance work as you would
like to, namely that not all virtual functions return *this.
In fact I have seen some time ago a proposal to allow a new kind of
member functions that would always return *this using the static type of
the argument. For example:
struct Base
{
this Method() // proposed syntax, not C++
{
// body here, "return value;" not allowed, "return;" allowed
}
};
struct Derived : Base
{
};
void test()
{
Base b;
Base& rb = b.Method();
assert(&rb == &b);
Derived d;
Derived& rd = d.Method();
assert(&rd == &d);
}
Notice that there are *no* virtual functions involved. It's all just
syntactic sugar. Method() is declared *and* implemented exactly as a
non-virtual function returning void, but the expression
o.Method()
is evaluated as
(o.Method(), o)
at the call site. I haven't heard of this proposal recently, does anyone
know if it has been formalized in some way? Anyway, although I like this
syntax very much, I acknowledge that the upcoming revision C++ has much
more important issues to consider.
Has anyone out there tried anything like this? I'm really trying to get
the named parameters idiom to work for a class hierarchy that allows
for sub classes to pass base class parameters back up to the hierarchy
seemlessly. Is there a better approach out there?
What about the Boost Parameter library <http://boost.org/libs/parameter/> ?
HTH,
Ganesh
---
[ 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.comeaucomputing.com/csc/faq.html ]