Boost logo

Boost Users :

Subject: Re: [Boost-users] Dynamically creating new units
From: OvermindDL1 (overminddl1_at_[hidden])
Date: 2009-12-25 22:19:31


On Fri, Dec 25, 2009 at 7:25 PM, Ray Burkholder <ray_at_[hidden]> 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:
>
> http://www.gotw.ca/publications/index.htm

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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net