473,770 Members | 2,153 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Pimpl Idiom

I've been going through some old code trying to clean it up
and rearchitect it based on more modern C++ idioms. In the
old code I often used the Pimpl idiom on a class by class
basis, creating impl within a class as such:

a.h
class A {
...stuff...
struct AImpl;
AImpl* _impl;
};

a.cpp

struct AImpl {
...stuff...
};

After doing this in a number of classes, I thought it would
be "cool" to have a single Pimpl class that any class
wishing to define implementation specifics could inherit
from and then define a class specific Impl class as such:

pimpl.h

class Pimpl {
struct Impl;
boost::shared_p tr<Impl> _impl;
};

a.h

class A : public Pimpl {
... stuff ...
};

a.cpp

struct A::Impl {
... stuff ...
};

This compiled okay, but then I ran into an inheritance
problem (as many of you probably predicted just reading
this):

b.h

class B : public A, public Pimpl {
};

I could use virtual inheritance, but I want 2 impl classes,
one for A's implementation specific stuff and B's
implementation specific stuff. Of course, I thought I would
use templates to parameterize each one to give it a
different type so.

pimpl.h

template <typename T>
class Pimpl {
struct Impl;
boost::shared_p tr<Impl> _impl;
};

a.h

class A : public Pimpl<A> {
};

b.h

class B : public A, public Pimpl<B> {
};
Still, this has not quite gotten me where I want to be. I
would like to be able to have an A::_impl and a B::_impl
that I can distinguish inside of B based on the methods that
have to be called. The other is that, if possible, I wish
to refer to them as A::_impl rather than Pimpl<A>::_impl and
likewise for B.

Any suggestions? Is this whole thing just bad form? Should
I just stick with the original approach?

Jay
Jul 22 '05 #1
7 7872
"Icosahedro n" <no***@nowhere. com> wrote in message
news:q0******** *************** @bgtnsc04-news.ops.worldn et.att.net...
I've been going through some old code trying to clean it up
and rearchitect it based on more modern C++ idioms. In the
old code I often used the Pimpl idiom on a class by class
basis, creating impl within a class as such:

a.h
class A {
...stuff...
struct AImpl;
AImpl* _impl;
};

a.cpp

struct AImpl {
...stuff...
};
Here I meant A::AImpl of course.

The idea behind "unifying" all the different Pimpls is that
a number of the impl classes must talk to each other within
the module. Rather than have friend declarations scattered
all throughout the heirarchy, I thought it would be better
to have a single Pimpl and make it a friend of itself, so
that the classes could interact within the module freely.
pimpl.h

class Pimpl {
struct Impl;
boost::shared_p tr<Impl> _impl;
};

a.h

class A : public Pimpl {
... stuff ...
};

a.cpp

struct A::Impl {
... stuff ...
};

This compiled okay, but then I ran into an inheritance
problem (as many of you probably predicted just reading
this):

b.h

class B : public A, public Pimpl {
};

I could use virtual inheritance, but I want 2 impl classes,
one for A's implementation specific stuff and B's
implementation specific stuff. Of course, I thought I would
use templates to parameterize each one to give it a
different type so.

pimpl.h

template <typename T>
class Pimpl {
struct Impl;
boost::shared_p tr<Impl> _impl;
};

a.h

class A : public Pimpl<A> {
};

b.h

class B : public A, public Pimpl<B> {
};
Still, this has not quite gotten me where I want to be. I
would like to be able to have an A::_impl and a B::_impl
that I can distinguish inside of B based on the methods that
have to be called. The other is that, if possible, I wish
to refer to them as A::_impl rather than Pimpl<A>::_impl and
likewise for B.
Of course, having two _impl members is impossible, but
having two GetImpl functions, each one with its own return
value would be possible, each addressed by its class prefix
(Pimpl<A>::GetI mpl() and Pimpl<B>::GetIm pl()) is what I'm
thinking for those classes which have two impls.
Any suggestions? Is this whole thing just bad form? Should
I just stick with the original approach?


Again, the above question still remains in effect.

Jay
Jul 22 '05 #2
Icosahedron wrote:
I've been going through some old code trying to clean it up
and rearchitect it based on more modern C++ idioms. In the
old code I often used the Pimpl idiom on a class by class
basis, creating impl within a class as such:
[snip] class A {
...stuff...
struct AImpl;
AImpl* _impl;
};
[snip] After doing this in a number of classes, I thought it would
be "cool" to have a single Pimpl class that any class
wishing to define implementation specifics could inherit
from and then define a class specific Impl class as such:
[snip] class Pimpl {
struct Impl;
boost::shared_p tr<Impl> _impl;
};
[snip] class A : public Pimpl {
... stuff ...
};
[snip - problem with multiple inheritance and general confusion] Any suggestions? Is this whole thing just bad form? Should
I just stick with the original approach?


The thing is, you don't want to inherit an implementation interface, you
want a *pointer* to an implementation object. This allows you to keep
the interface and implementation separate, alleviating compile time
dependencies, and improving encapsulation. So, your entire question is
ill concieved, IMO. Stick to the original plan.

/david

--
"As a scientist, Throckmorton knew that if he were ever to break wind in
the echo chamber, he would never hear the end of it."

Jul 22 '05 #3
> [snip - problem with multiple inheritance and general confusion]
Any suggestions? Is this whole thing just bad form? Should
I just stick with the original approach?


The thing is, you don't want to inherit an implementation interface, you
want a *pointer* to an implementation object. This allows you to keep
the interface and implementation separate, alleviating compile time
dependencies, and improving encapsulation. So, your entire question is
ill concieved, IMO. Stick to the original plan.


A good point. The reason I chose to do this (and not explained in the
original post) was that in a suite of classes I am using, often one class'
impl must gain
access to another classes impl, but might only have the reference to the
envelope class.

class A {
private:
struct Impl;
Impl* _impl;
friend class C;
};

class C {
public:
void DoSomething(A* a);
private:
struct Impl;
Impl* _impl;
};

where C might need to get something out of A's impl or call a method on it.

C::DoSomething( A* a)
{
a->_impl->DoImplSpecific Stuff();
}

How would you design this so that the friend statements aren't necessary?
Since the impls are hidden anyways, making them public really doesn't expose
any functionality, so I could do it that way, but of course that's not
really
elegant. I appreciate the feedback.

Thanks,

Jay
Jul 22 '05 #4
"Icosahedro n" <no***@nowhere. com> wrote in message news:<L0******* **************@ bgtnsc05-news.ops.worldn et.att.net>...
[snip - problem with multiple inheritance and general confusion]
Any suggestions? Is this whole thing just bad form? Should
I just stick with the original approach?


The thing is, you don't want to inherit an implementation interface, you
want a *pointer* to an implementation object. This allows you to keep
the interface and implementation separate, alleviating compile time
dependencies, and improving encapsulation. So, your entire question is
ill concieved, IMO. Stick to the original plan.


A good point. The reason I chose to do this (and not explained in the
original post) was that in a suite of classes I am using, often one class'
impl must gain
access to another classes impl, but might only have the reference to the
envelope class.

class A {
private:
struct Impl;
Impl* _impl;
friend class C;
};

class C {
public:
void DoSomething(A* a);
private:
struct Impl;
Impl* _impl;
};

where C might need to get something out of A's impl or call a method on it.

C::DoSomething( A* a)
{
a->_impl->DoImplSpecific Stuff();
}

How would you design this so that the friend statements aren't necessary?
Since the impls are hidden anyways, making them public really doesn't expose
any functionality, so I could do it that way, but of course that's not
really
elegant. I appreciate the feedback.

Thanks,

Jay


This may be telling you that the pimpl idiom is not well suited to your application.

Jack
Jul 22 '05 #5

"Icosahedro n" <no***@nowhere. com> wrote in message
news:q0******** *************** @bgtnsc04-news.ops.worldn et.att.net...
I've been going through some old code trying to clean it up
and rearchitect it based on more modern C++ idioms. In the
old code I often used the Pimpl idiom on a class by class
basis, creating impl within a class as such:

[snip]
Still, this has not quite gotten me where I want to be. I
would like to be able to have an A::_impl and a B::_impl
that I can distinguish inside of B based on the methods that
have to be called. The other is that, if possible, I wish
to refer to them as A::_impl rather than Pimpl<A>::_impl and
likewise for B.

Any suggestions? Is this whole thing just bad form? Should
I just stick with the original approach?


FWIW, I finally got what I wanted, more or less. Here's a sample showing
what I've done so far. Amazing how simple these things always seem to boil
down to.

#include <iostream>

using namespace std;

template <typename T>
struct Impl;

class C;

class A {
struct Impl<A>* _impl;
template <class T> friend class Impl;
public:
A();
};

class B : public A {
struct Impl<B>* _impl;
template <class T> friend class Impl;
public:
B();
void Print(C*);

};

class C {
struct Impl<C>* _impl;
template <class T> friend class Impl;
public:
C();
};
struct Impl<A> {
A* that;
Impl(A *a) { that = a; }
void Print(void) { cout << "In Impl<A>::Print" << endl; }
};

struct Impl<B> {
B* that;
Impl(B *b) { that = b; }
void Print(C* c);
};

struct Impl<C> {
C* that;
Impl(C *c) { that = c; }
void Print(void) { cout << "In Impl<C>::Print" << endl; }
};

A::A() : _impl(new Impl<A>(this)) {}
B::B() : _impl(new Impl<B>(this)) {}
C::C() : _impl(new Impl<C>(this)) {}

void Impl<B>::Print( C* c)
{
cout << "In Impl<B>::Print" << endl;
that->A::_impl->Print(); // shows accessing a base class' impl
c->_impl->Print(); // shows accessing another class' impl
}

void B::Print(C* c)
{
cout << "In B::Print" << endl;
_impl->Print(c); // forward to impl class
}

int main(void)
{
C c;
B b;
b.Print(&c);
}

As you may see, I dropped the Pimpl being inherited. I don't know why I was
thinking it, but I was doing that to allow for the automatic declaration of
the Impl class, which would force the implementer to define a nested Impl
class. Unfortunately, there is no way to extend friendship between these
classes to the nested Impl classes or the main classes well.

As for the Pimpl idiom being correct or not for this application, I chose it
because it is a cross platform application wherein I wanted the
implementation specific details to be kept out of the interface classes
(though truthfully the interface classes contain data common to all
platforms too, so they are not pure interface classes). I could have just
defined the methods themselves for the classes on a platform by platform
basis (each implementation for A could have been in separate directories for
instance), and just kept the data in the impl structures, which would have
worked I believe, and still given me the same opacity with regards to the
specifics, but I wanted the freedom to add methods instead of just helper
functions, though the distinction is pretty moot.

The main reason I wanted this was that in my particular application, a
renderer, the impl classes need access to details in other impl classes
(such as texture id from the TextureImpl for setting the current texture in
the CameraImpl class), and I didn't want to have to have friends defined for
every particular combination. (The friends were required because to get to
the _impl member of another class required that you have access to the
private members of that class.) I could have done it one of several ways I
believe:

1) make the _impl member public - this means anyone can access it, but
without the interface, it's pretty hard to do anything with it. This also
could be done also with a GetImpl member function. Opaque, but not guarded
from modification well.

2) friends. Of course there's the obvious friend class declaration, but as
mentioned, for every shader for instance, the Camera::Impl would have to be
put in, and likewise each Shader::Impl would have to be listed in Camera.
And that has to be in the main header file, not the implementation files.
Or, I could do as I did and make all the Impl classes friends by default
with one line. Not perfect, but done only once and still get the benefits
of hidden implementation and access restriction from the outside.

Along with #2, I am considering this is being designed to allow extension by
other developers (with their classes being first class members of the
library as well rather than some hacked in extension mechanism), I wanted
some way for them to add to the library without having to add their classes
as friends to the main classes.

So, the main mechanism is that you have to have an Impl<T> member named
_impl and a friend declaration "template <class T> friend class Impl;" that
will automatically define other Impl<T> classes in the module as friends of
the class. I keep the Impl class definition in the Render namespace, to
avoid any potential conflicts and to preserve some semblance of module
integrity.

Well, that's the short of it. Please feel free to comment, as I do read
them, if I don't respond to each one. Thanks again.

Jay

P.S. The above code compiles fine on GCC 3.2.3
Jul 22 '05 #6
Hi Jay,
... in a suite of classes I am using, often one class's impl must gain
access to another class's impl, but might only have the reference to the
envelope class.
[e.g.]
C::DoSomething( A* a)
{ a->_impl->DoImplSpecific Stuff(); }

How would you design this so that the friend statements aren't necessary?


This is a design issue. Imagine what you're saying: you're
encapsulating stuff by making it private in class A, and then you're
specifically breaking (or at least dramatically reducing) the
encapsulation by having class C use private member functions in class
A. The classes are now more tightly coupled ... a change in class A
may necessitate a change in class C (suppose A::DoImplSpecif icStuff()
disappears, etc) If class C wants to be able to call a member
function in class A, it should be public.

Optionally, you could define a separate friend class of A that has the
helper function in it, and have both A and C call that (I believe this
is better than having C be a friend of A, since C itself doesn't
really need to be a friend to /all/ of A, it just needs a specific
function ... sorry, don't have time to really explain myself on this,
and I'm kind of shooting from the hip, it might be a crappy idea).

Anyhow, keep thinking about the design. I don't believe that
"friendship " is the right answer here, and you can probably come up
with something better that is more encapsulated. Good luck!

Jeff
Jul 22 '05 #7
> This is a design issue. Imagine what you're saying: you're
encapsulating stuff by making it private in class A, and then you're
specifically breaking (or at least dramatically reducing) the
encapsulation by having class C use private member functions in class
A. The classes are now more tightly coupled ... a change in class A
may necessitate a change in class C (suppose A::DoImplSpecif icStuff()
disappears, etc) If class C wants to be able to call a member
function in class A, it should be public.
True. Actually, the only thing I need is access to the _impl class member
so I can call impl specific functions from another impl specific class in
the module, but I don't know of another mechanism to grant that.
Optionally, you could define a separate friend class of A that has the
helper function in it, and have both A and C call that (I believe this
is better than having C be a friend of A, since C itself doesn't
really need to be a friend to /all/ of A, it just needs a specific
function ... sorry, don't have time to really explain myself on this,
and I'm kind of shooting from the hip, it might be a crappy idea).

Anyhow, keep thinking about the design. I don't believe that
"friendship " is the right answer here, and you can probably come up
with something better that is more encapsulated. Good luck!


Thanks. I see what you're saying. I posted a general response to this.
You are right about the classes being tightly coupled, and you are right
about this breaking encapsulation, but at least in my mind it does so within
the module, and so really isn't breaking modular encapsulation.

As for the A->B->C link, I see what you're saying. I think that makes more
complication within a module where things are tightly coupled by nature, but
it is a good idea for keeping encapsulation.

I'll have to rethink what I've got and perhaps come up with something else.
I originally wrote a long essay about why what I was doing was the right
thing, and I still think it is the easiest within the module, but perhaps I
can rethink what I'm doing internally to make it not necessary.

Jay
Jul 22 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
2190
by: Asfand Yar Qazi | last post by:
Hi, Now that GCC 3.4 has precompiled headers, I'm thinking I can stop using pimpls to speed up development time, as it may make life easier (declaring pimpls takes a long time...) What are the views of the experienced users of various C++ implementations? Do precompiled headers allow pimpls to be avoided while maintaining the same speed up of development time?
2
4050
by: Debajit Adhikary | last post by:
I'm still pretty new to design patterns... I was wondering, is there any difference between the Bridge Pattern and Herb Sutter's Pimpl Idiom? Both delegate responsibility to an implementation and thus allow a clear and flexible separation of interface and implementation such that the implementation can be changed freely.
2
6114
by: Peteris Krumins | last post by:
Hello! I was playing around pimpl idiom and discovered that there is a problem with it if a class member template function exists which has to access private data, since only the forward declaration of pimpl class is provided. Example:
9
1562
by: Edward Diener | last post by:
Because 'friend' is not recognized in MC++, using the pImpl idiom in MC++ classes seems nearly impossible. Normally a pImpl class is a 'friend' to the class for which it supplies the private implementation, so that it can access any protected members, including inherited protected members, of that class. Without 'friend' the pImpl class can no longer do this, and it is a PITA passing the necessary protected data or protected member function...
10
4498
by: red floyd | last post by:
It seems that the use of auto_ptr<> is discouraged in many places in favor of boost::shared_ptr<> (or tr1::shared_ptr<>). But consider a PIMPL idiom, where there is a strict 1-1 relationship between interface objects and implementation object, and the implementation object lasts for the lifetime of the interface object. i.e. // header file class WidgetImpl; class Widget {
34
3706
by: Asfand Yar Qazi | last post by:
Hi, I'm creating a library where several classes are intertwined rather tightly. I'm thinking of making them all use pimpls, so that these circular dependancies can be avoided easily, and I'm thinking of making all these pimpl class declarations public. Reasoning is that since only the code within the ..cc file will need to ever access them, why protect them in ways that would make access to them more difficult and obfuscated? What...
4
3833
by: Noah Roberts | last post by:
Some little tidbit I just ran into that might help some, especially novice programmers. If you are using the pimpl idiom, as you probably should be most of the time, then it is very straightforward to turn your class into a singleton object. Consider: class X { struct impl;
14
3176
by: Daniel Lidström | last post by:
Hello! I have just discovered a way to use the private implementation idiom (pimpl), without the overhead of dynamic memory allocation. For those of you who don't know what this is, Wikipedia has a nice article you can read. Anyway, I discovered that if you make all members in the implementation class mutable, you can in fact use this idiom without any "unnecessary" memory allocation. Here's a minimal example of the method: // In the...
2
2230
by: Graham Reitz | last post by:
What are good strategies for selecting, either at run-time or compile time, various pimpl'ed implementations? While retaining the ability to switch implementations without recompiling. Boost has an example but with only one implementation class: (what would an example with 2 implementation classes look like?) http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/sp_techniques.html#pimpl The pimpl'ed class cpp file has to include at...
0
9425
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10228
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10057
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9869
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7415
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6676
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5312
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3970
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3575
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.