[linux-audio-dev] (OT) C++ flame war

Martijn Sipkema m.j.w.sipkema at student.tudelft.nl
Thu Feb 6 10:27:01 UTC 2003


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

> the kinds of problems i have with C++ stem from the fact that you
> cannot mark a section of protected members as accessible from only a
> particular set of friends. the only way to say "only class Foo can
> access these member (functions)" is to create a separate class, make
> Foo a friend of that class, and then inherit from it.

This really is a different problem.

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
an object. Declaring a class A friend of another class B is saying that all
member functions of A have access to the private part of class B. This
should only be done to exporess closely connected concepts.

When possible other  classes should interact using a class' public
interface(s).

> this gets really messy really soon. the editor object in Ardour
> contains many distinct sets of functionality that i would really like
> to partition.

So, derive from various abstract classes that provide interfaces
for these sets of functionality.

> i could create a set of discrete classes that cover each
> aspect of the functionality, and then do MI from all of them. the
> problem is that is each one of these aspects *internally* needs to
> know about the others, which now means that they each have to be
> friends of each other. so what's the point? i'd end up with something
> ludicrous like:
>
>   class EditorFoo {
>      ...
>      protected:
>         friend class EditorThis;
> friend class EditorThat;
> friend class EditorTheOther;
> ...
> friend class ObjectThatInteractsWithEditorFoo;
> ...
>          };

Here EditorFoo is not a abstract class.

>
> ...
>
> class Editor : public EditorFoo, EditorThis, EditorThat,
>                EditorTheOther .... {
>          }
>
> which is really no help at all.

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.

Note that your problem is still different as with using friends in such a
manner the classes using the editor are dependant on its implementation
and also don't use the editor's public part only.

> the other alternative is to use HAS-A
> instead of IS-A, and its even worse. we end up with lots of code like:
>
> editor->foo->...
> editor->that->...
> editor->theother->...

This is an option.

> all i'd really like it to be able to say:
>
>        class Foo {
>           protected:
>       /* scope A */
>       friend class Bar;
>       ...
>           protected:
>       /* scope B */
>       friend class Baz;
>       ...
>        };
>
> such that Bar can only access stuff within "scope A" and Baz can only
> access stuff in "scope B". that is, access control keywords
> ("private", "protected", "public" define access scopes). right now, a
> friend class declared anywhere within the class declaration is a
> friend, period.

Correct. But perhaps you are misusing the friend concept. Are these
friend classes so closely related that they cannot use some public
interface?

> 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 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
of a class in the header. If you want to be seperated from the
implementation, use an abstract class. But then you cannot create
a class instance, you can only use the provided interface on an already
created instance (, but you can delete it when there is a virtual destructor
in the interface).


> 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).

--ms






More information about the Linux-audio-dev mailing list