
On Fri, Dec 25, 2009 at 7:25 PM, Ray Burkholder <ray@oneunified.net> wrote:
I think this falls under the PIMPL idiom, which is described by Herb Sutter at:
http://www.gotw.ca/publications/mill04.htm http://www.gotw.ca/publications/mill05.htm
with more generically useful articles at:
Not generally. I am not really a proponent of Pimpl. The C style gives you complete abstraction, not even any overhead of the Pimpl, and anything is visible only through functions. As much as many idiots like to say, the C++ OO style is *not* OO. In C++, lets take this class: class anotherClass; class myStuff { private; int i; float f; std::string s; public: void doOperation(anotherClass *c); } Now, that can let you do things like: anotherClass *a = fromSomewhere(); myStuff *m = fromSomeplace(); m->doOperation(a); Now this is no where near real OO as it was originally described. Of all programming languages, CLOS gets the closest to real OO, and in pseudo-C++ that would be more like: class anotherClass; class myStuff { int i; float f; std::string s; } void <myStuff*> doOperation(anotherClass *c); Hence you could do things like this still: anotherClass *a = fromSomewhere(); myStuff *m = fromSomeplace(); m->doOperation(a); Although, doOperation(m,a) might be better if the function were defined as: void doOperation(myStuff *m, anotherClass *c); However, if both myStuff and anotherClass are virtual and can have different base classes, you can still only switch based on the first. Continuing in a pseudo-C++, what if: class base1 {}; class base2 {}; class child1a : virtual base1 {}; class child1b : virtual base1 {}; class child2a : virtual base2 {}; class child2b : virtual base2 {}; void doOperation(virtual base1 *b1, virtual base2 *b2, int i); // base overload void doOperation(virtual child1a *c1a, virtual child2a *c2a, int i); // overload 1 void doOperation(virtual child1b *c1b, virtual child2a *c2a, int i); // overload 2 void doVB1(virtual base1 *b1, base2 *b2); // overload first void doVB1(virtual child1a *c1a, child2a *c2a); // overload second // Now we have some filled pointers base1 *b1 = get_b1(); base2 *b2 = get_b2(); child1a *c1a = get_c1a(); child1b *c1b = get_c1b(); child2a *c2a = get_c2a(); child2b *c2b = get_c2b(); base1 *t1; base2 *t2; // Now to use it t1=b1;t2=b2; doOperation(t1,t2,0); // calls base overload t1=c1a;t2=b2; doOperation(t1,t2,0); // calls base overload t1=c1a;t2=c2a; doOperation(t1,t2,0); // calls overload 1 t1=c1a;t2=c2b; doOperation(t1,t2,0); // calls base overload t1=c1b;t2=c2a; doOperation(t1,t2,0); // calls overload 2 t1=c1b;t2=c2b; doOperation(t1,t2,0); // calls base overload t1=c1a;t2=c2a; doVB1(t1,t2); // calls overload first doVB1(t1,c2a); // calls overload second, because it needs to be explicit due to no 'virtual' And so forth, and of course it can be extended to more then 2 virtuals as well. If you notice, the virtual tables are built per call site based on what doOperation's are visible at that point. If there is a doOperation that defines it for child1b* and child2b*, it would not be in this overload resolution table because it is not visible. For conflicting overloads, like this: // a diamond inheritance: class child1ab : virtual child1a, virtual child1b {}; void doOperation1(virtual base1 *b1a, virtual base1 *b1b, int i); // overload base void doOperation1(virtual child1a *c1a, virtual child1b *c1b, int i); // overload A void doOperation1(virtual child1b *c1b, virtual child1a *c1a, int i); // overload B You can either do something like just throw an exception due to ambiguity if called with this: t1 = t2 = new child1ab; doOperation1(t1,t2,0); Or you can also (and this is what is more commonly done) use the most complete and unambiguous overload, which in this case would be the overload base. Although you would probably want to issue a warning at compile time since you have the nice safety of the C++ type system unlike in CLOS regardless of what you choose. The nice thing about this style, your class definitions can be pretty completely forward declared (change the syntax for a forward declaration can take an inheritance list, you do not need to generate a size for it since we are only using pointers, but the inheritance list would be all we would need for virtual type resolution. C++ was poorly designed with regards to classes in the first place, if it went this way we would have more power, faster compile times, etc...