[...]
i love C++. i think its one of the best things
ever. but i happen to
agree with Erik. the solution proposed by martijn doesn't scale well,
and doesn't really address the issue in a comprehensive way. it
requires one pure virtual class per distinct set of private members,
for a start.
No, it requires a pure virtual class per distinct interface (abstract
class). And I don't see why this would not scale.
you should try writing ardour :)
A friend is just like a member function, i.e. it can
access the
class' private data, but it is not in the class' scope and the
function is not invoked on
i know what a friend *is* - i was trying to convey what i want a
friend to be in the best of all possible worlds.
When possible other classes should interact using a
class' public
interface(s).
the point is that i want semi-public interfaces that are not
implemented via abstract classes or inheritance because they cover
functionality that is still tightly coupled to the rest of the object.
by making them abstract, i can solve the coupling at the
implementation level (because the implementation only exists in the
concrete classes). but i still find this really messy.
conceptually, i am not creating a distinct type of object - i want to
provide a particular set of objects with access to a limited set of
member functions belonging to an otherwise unified object. C++ won't
let me do that - it forces me to use an abstract class, multiple
inheritance and virtual functions to get the job done. being able to
limit the scope of a friend declaration would solve this problem in a
much more natural way, i think.
class A { // some interface
public:
virtual void a() = 0;
};
class B { // another interface
public:
virtual void b() = 0;
};
class editor : public A, public B { // the editor provides both interfaces
public:
void a();
void b();
};
and now a class C that wants to use the functionality of the editor that is
exported by interface A can use it like:
void f(A& i) {
i.a();
}
without depending on the implementation.
this is precisely the solution i find so cumbersome. an editor is not
an A, and a B and a C and a D. its an editor. the point is that only
certain other things should be able to call a() and other things
should be the only ones to call b(). its very unnatural to declare
this in this way, although yes, i know that it works.
Correct. But perhaps you are misusing the friend
concept. Are these
friend classes so closely related that they cannot use some public
interface?
as i said above, the interfaces are not public. they are intended to
be restricted just to the specified other classes.
none of this
helps with the problem erik identified.
The problem Erik identified was that one could not seperate the
interface from the implementation in C++. I then said this can be
done using an abstract class, i.e. an interface.
i would accept that this is true for relatively simply objects. i just
don't think it scales well. the current ardour editor has about 7000
lines of code, the object itself has about 800 members (either data or
functions). splitting this up is a non-trivial exercise.
nevertheless, it could truly be worth doing. the compilation
dependencies right now are horrendous. changing editor.h requires me
to wait about 10 minutes for a recompile :)
i would
really
love a C++ that did this:
class Foo {
public:
... stuff ...
private:
<some tokens that meant something like #include>
};
and then in other files, you would do:
#use "foo.h"
or
#implementation "foo.h"
or something like that. the first one would just bring in the public
declarations, and its what you'd use when you're calling or creating
Foo objects. the second one would be used in the definitions for the
member functions of Foo, and hence would almost certainly be limited
to "foo.cc".
It doesn't work that way. You cannot create an class instance without
its full declaration. I don't see the problem of having the private part
i don't believe that this is true. the actual code executed by
constructor is the only thing that needs to know the full
declaration. the one exception is creating objects on the heap, where
we need a size so that we can allocate memory, and then run the
constructor using the returned address. i'd be happy with a language
where
x = new Foo;
really translates to:
x = Foo::constructor (malloc (Foo::sizeof());
where ::sizeof() is a built-in compiler-generated virtual.
note that the
private stuff would be in a file that looked just like
the class declaration, but had no public (and protected?)
declarations. in other words, the class declaration it includes is
implicitly 100% private, but it can include header files that are
necessary for the private declarations.
I don't see what this would solve and I don't think this is even possible.
Changing the private part will break binary compatibility (without
changing the public header).
the dependency part is easily solved by the compile system. given the
new preprocessor directives it would require anyway, you'd just
generate dependencies that included the private part. then if the
private part changes, even though its never read by the users of the
public interface, they are recompiled too.
anyway, its water under the bridge. C++ doesn't do this, and will
likely never do this.
--p