>[...] >> 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