Re: extending c++ classes and enumerations
perrog@gmail.com wrote:
James Kanze skrev:
But you still haven't given a concrete example of exactly what
benefits you're referring to, and what C++ in particular offers
to provide those benefits.
To put it simply, I need to write less code in C++ than I would do in
C. C++ provides syntax short-cuts. I'm very lazy, and if there are
statement that make initialization, error checking, operands, etc into
simplier expressions and statement, I don't mind.
In C, I write
extern struct button *btn;
int foo_button(struct drag_session *di) {
struct drag_data dd;
drag_data_init(&dd);
if (drag_data_set_session(&dd, di) < 0)
return -1;
if (drag_data_copy_data(&dd, button_get_data(btn)) < 0)
return -1;
// ...
if (drag_begin(di, &dd) < 0) {
void *ptr = drag_data_get_data(&dd);
if (ptr != NULL) free(ptr);
if (drag_data_release(&dd) < 0)
; // ignore errors from release
}
};
Besides this soup, there may be ten other function doing similar work.
In C++, I use classes and templates resulting in all ten functions
becomes reduced to one function with tree lines:
class DragSession {
// prerequisites: class Responder implements getData()
template<typename Responder>
void foo(Responder &responder) throws(DragException) {
DragData dd(responder.getData());
dd.setSession(this);
beginDrag(dd);
}
};
This is something i felt beeing lexical (or syntaxical) benefits!
In sum, if I understand correctly, you want something equivalent
to the implicit this-> you get within a class. I'll admit that
I've never found it a problem not having it outside the class.
And I don't mind typing a little more to keep my abstractions
clear and separate. When that's not important, I'll just write
in AWK, rather than C++, and save all my data declarations,
etc., as well.
I don't have the complete implementation in my head, but from
what I remember, most of that "extra code" is in (private)
member classes. And of course, the implementation of
basic_string doesn't hesitate to make use of lower level
abstractions which are available (e.g. atomic_add, or whatever
the name is).
And I'm not sure what you're trying to get at. The GNU
implementation of basic_string most obviously doesn't need the
possibility to extend classes---the proof is that they
implemented it without implementing this ability.
Ok, then you could consider another scenario where a third-party
library "libfoo" delivers classes for say data-base management. The
vendor doesn't utilize own container classes, but neither use ANSI
standard classes. However, By using template mechanism the library will
be independend of what e.g. string implementation is used, the only
requirements is that the string model implements certain kind of
methods
/*
// Unfortunately, the vendor choosed java.lang.String naming style
// not std::string names.
model String {
String(const String &lhs);
String &charAt(int index);
int compareTo(const String &lhs);
int length();
// ...etc
};
// There will be similar function prerequisites for
// Arrays, Maps, Lists, etc.
*/
template<class String> Query { ... };
template<class String, ...> Database { ... };
(The C++ template mechanism where parameter's prerequisites is not
fulfilled, is catched by the compiler.)
Now, we decide to use ANSI C++ containers in our program. Since the
libfoo expects java.lang.String names, we must sub-class std::string
and add those java named methods.
Have you ever seen such a case? Where a third party library was
templated on a string type? Sounds a little stretched to me; if
the library is doing anything non-trivial, templates are out,
and all the third party libraries I know either use char* or
their own string class. It's not a reasonable scenario.
And of course, you'd probably not subclass here---it's not
generally a good idea to derive from std::string, and in this
case, the relationship you're looking for is "implemented in
terms of", which means a member, and not a base class. Of
course, this means more typing, but it keeps the two different
abstractions separate. The result is code that is cleaner and
easier to understand.
The statement "the encapsulated code isn't part of the real
encapsulation" suggests that you're thinking along the lines of
something like the code in the StringUtils.hh file of
http://kanze.james.neuf.fr/doc/en/Text/html/index.html. (The
actual code can be found at
http://kanze.james.neuf.fr/code-en.html.) But there again, the
possibility to extend a class obviously isn't needed, since the
code exists, despite the lack of this possibility. Allowing the
extension of the class would have two effects on this code:
1. it would allow the user to write s.trim(), rather than
trim(s), and
2. it would allow the actual code of trim() to access the
private implementation of basic_string, and thus violate the
invariants of basic_string.
Point one could easily be handled by a simple extension allowing
the use of member function syntax for free functions (and why
not, the inverse as well); if such a proposal has never been
made, I suspect that it is because no one has really felt that
this was a problem which needed solving.
Most peoples would probably add free functions (prefixed with the
namespace and class name to avoid return ambiguity) or sub-class the
original class.
In this case, the original class is std::string, and I don't
think any competent programmer would derive from it for this.
My own code is just a set of free functions.
That's okay, but then your function may become
incompatible with other lexical or syntaxical benefits with C++, e.g.
member function pointers.
Why should it be compatible with member function pointers?
Only because it has never been proposed,
doesn't mean it is not needed.
By the way, a member function-like syntax for free functions is already
semi-implemented. Adding
namespace my { class object { ... }; }
std::ostream &operator<<(ostream &rhs, my::object &lhs) { ... }
could also be achieved by adding a member function to std::ostream. :-)
Which would buy us?
I don't see your point (and I haven't seen Ondrej's posting
yet), but derivation does NOT allow accessing private members.
That is the key point. The fact that a class is closed is a
basic principle in C++, and the basis of C++'s support for
encapsulation. Remove it, and there is no fundamental
difference between classes and namespaces.
That would be another possibility if namespace names could be combined
with class names to put constants and functions under its label scope.
But will free function automatically become class' member function,
then?
No. You don't seem to understand: the key difference between a
member function and a non-member function is that the member
function can access private parts of the class; the non-member
can't. And that making a class closed with respect to which
functions can access private elements is an essential part of
encapsulation. Thus, for example, a free function can access
private parts of the class, but only if it is declared friend
within the class.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientie objet/
Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]