|
||||||||||||||||||
Add Forum to Favorites | Send Topic To a Friend | View Forum FAQ | Track this topic |
Last Thread Next Thread ![]() |
| The C++ Pimpl |
|
![]() desbrowne Member since: 2/17/2002 From: Australia |
||||
|
|
||||
| I thought at first that it must have been a new skin condition that teenagers get As for the _ in variable names; YUCK! Otherwise it was an excellent article, concise and to the point. Well explained. |
||||
|
||||
![]() abdulla Member since: 3/31/2001 From: Melbourne, Australia |
||||
|
|
||||
| to not pollute the global namespace, you could use an anonymouse namespace |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| Don't take this the wrong way, but if there is already an article about it at www.gotw.ca, what does your one add? Also, you don't explain what the advantage of using pimpl is. |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| If the goal you're setting up is the only one, I'd rather use an interface. E.g. typedef struct interface; ... interface IPublicClass { virtual void SomeFunc() = 0; // pure virtual }; ... class PrivateClass : public IPublicClass { public: virtual void SomeFunc(); // actual implementation private: ...blah... }; So the outside world can use IPublicClass*'s. Far cleaner than having those nasty proxy methods, and LESS speed penalty because you're not sending those arguments a second time. Okay, this inhibits certain things but in those cases (inlining, template stuff) you'll need to expose the implementation anyway. // aav |
||||
|
||||
![]() Stoffel Member since: 12/2/1999 From: San Diego, USA |
||||
|
|
||||
quote: "The Pimpl idiom describes a way for making your header files impervious to change. You often hear advices like "Avoid change your public interface!" So you can modify your private interface, but how can you avoid recompilation when your header file defines the private methods. This is what the Pimpl does – Reduce compilation damages when your private interface changes." Seems pretty straightforward to me. The pImpl is a great technique in large projects. Good article. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: You will be amazed by the # of people who don't read or understand Guru of Week yet claim they are C++ gurus. My idea is to introduce you to better C++ coding techniques. Of course I can't just have an article that says, "Go to www.gotw.ca and read item # on pimpl", can I? As for the advantage of pimpl, it reduces make dependencies when compiling. I think I explained it pretty clearly in the abstract. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: This is a totally different topic. If you need to expose the implemetation, then you are introducing a additional dependency that can be avoided using the pimpl. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: I'm not sure if I understand what you mean. If you meant to put the private implementation class in an annoymous namespace in a header file, then it accomplishes nothing. |
||||
|
||||
![]() siaspete Member since: 10/10/2001 From: Edinburgh, United Kingdom |
||||
|
|
||||
| I think I'm another one that doesn't get why this exists. It seems to me that using an abstract base class solves this problem. As far as I can tell, using a pImpl is effectively reimplementing the vtable. Helpful links: How To Ask Questions The Smart Way | Google can help with your question | Search MSDN for help with standard C or Windows functions |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
quote: So it is... that's why I mentioned it. The reason why I posted about the interface/abstract baseclass method was that, as siaspete also says, the article doesn't pose any problems that make the pimpl method seem better than the above. // aav |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
| In your abstract interface case, any file that includes the PrivateClass needs to recompiled if you add/remove private methods. (And somewhere you do need to include PrivateClass in order to create a pointer to the abstract interface.) In places where your header shouldn't change (e.g. dlls), you can safely replace the dll without recompiling the client. Of course, one would probably choose COM but that's OT here. If you still can't see the point, either try it out or read it more at the Guru of the week. |
||||
|
||||
![]() siaspete Member since: 10/10/2001 From: Edinburgh, United Kingdom |
||||
|
|
||||
| Cheers Void. You're right, there must be some good advantage to using this, but I just can't see it at the moment. I'll have a read about the web and see what I can find out. At the moment though there doesn't seem like there's anything that using this does that is better than ABCs. Helpful links: How To Ask Questions The Smart Way | Google can help with your question | Search MSDN for help with standard C or Windows functions |
||||
|
||||
![]() Stoffel Member since: 12/2/1999 From: San Diego, USA |
||||
|
|
||||
| The problem with ABCs is that it's difficult to create a concrete object. You can make a static "makeme" method, but that's cheezy. Besides, if the point is to insulate the user from internal details, inheritence is the wrong thing to be using. To quote Sutter himself (and this should also be etched in stone and pounded into the head of every new programmer): "Inheritance is often overused, even by experienced developers. Always minimize coupling. If a class relationship can be expressed in more than one way, use the weakest relationship that's practical. Given that inheritance is nearly the strongest relationship you can express in C++ (second only to friendship), it's only really appropriate when there is no equivalent weaker alternative." Composition, especially that of a single pointer to privately-defined class, is just about as weak as you can get. If you don't believe the ramifications of this, imagine you are writing a commonly-included class (say error reporting, or just trace logging) that is used by every module in your program, and that a full recompile takes about 4 hours. With the pImpl, once you set your public interface, client modules never have to recompile. |
||||
|
||||
![]() Charles B Member since: 1/17/2002 From: France |
||||
|
|
||||
| If == and () are unset why not simply separate public (user) side headers and private+public side headers ? This could be used for low level classes and no extra dereferencement is required. I never did it before but I imagine it's the equivalent of a C lib/module where static functions are hidden to the user. Am I wrong ? To me the only pb is potential misadressing. Thus the public data, probably required by inlined public methods, must be carefully declared ahead and not modified. But that could be part of the "interface contract". Linker/Compiler dependent issues ? I dont say it would work in all cases but in some low level cases it could be useful. But then beware private virtual methods. I am not really sure about what could happen ! LOL I like to practice different styles depending on the hi/lo level of programming. The best thing for global efficiency AND stability. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: To further clarify what stoffel has said, the main problem with the ABC is the public heritance. What may actually happen (and often) is that your class is already a subclass. This is where you stepped into the dreaded multiple inheritance area. And with it comes lots of problems when you are using public inhertiance when the relationship is not a IS-A. It's pretty easy to set the benefit of pimpl vs the abstract class method. Just look at the # of files that has to be recompiled when you add a private method. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: That is the ultimate goal of the pimpl but it can't do it without the additional dereference. I'm not sure what you mean by separating having seperate sets of headers. Unless what you mean is to replace all the private member functions with non-member functions inside it's own private implementation file, I can't see how this is possible. (But then you need to pass the class instance around, so it's amounts to the same thing) If you are talking about some platform specific function address rebasing scheme, then I'm not interested. 8( |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| Yes, the ABC/interface case requires some kind of "creator" entity that is decoupled from the private implementation -- naturally. Otherwise the whole point would be missed. But it's rarely a problem, you usually DO have a natural place to put those creators, in a parent manager object or something like that. OOP systems tend to be hierarchical in nature, and you always have the toplevel namespace. This is the basis of COM and similar 'patterns', I don't personally have a problem with it. And I still think this is far less evil than definining wrapper methods for everything. // aav |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
quote: It is possible to solve many of these cases by templatizing the privately used baseclass (class Private : public MyBase<IFoo> etc) but yes, it's a problem. However, I've found that inheritance can often be avoided in general, and there's a good chance you can avoid it on the publically exposed classes specifically. Public interfaces should be kept simple and in small numbers anyway. // aav |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: I have limited experience with COM, but from what I seen it, it turns C++ class into C interface by rebasing using really ugly macros. Can you add private methods to an interface once it is etech in the COM? Or must you get the next version of the interface? This must be done without recompiling the client. Say, for using classes with dlls, you would want to avoid recompiling the client, the usual(?) practice is to pass a void pointer to the dll and the dll would initialize the pointer. The pimpl would be pretty useful here. |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
quote: Well MS's bloated COM can do that, but I was more comparing it to the "pattern" of having an ABC-based interface and creators. COM does not automatically mean ugly macros. It can be as simple as I've described. quote: For this whole thing to work, the compiler must only be able to create "COM-patible" vtables. The only "contract" between the user code and the private implementation is the vtable (the public interface). So you can modify the private implementation all you want, as long as the public interface remains the same. Most compilers on win32 should either directly produce or have an option to enable support for this "binary vtable standard". Pimpl does not offer this kind of binary compatibility between different compilers, as it 1) doesn't use virtual functions and even if it would, 2) it uses proxy CODE to communicate with the DLL. Again, not saying there isn't a use for Pimpl, but the problems presented so far are MUCH simpler to solve with interfaces. // aav |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
| Forgot to inform you, I prefer non compiler/platform specific solutions. 8) I think we are reaching the "apples and oranges" talk. The pimpl is not only useful for external interface but internal modules. Which is where the power shines because you don't have to recompile the whole project when you change a highly dependant module. Though nothing is stopping you, you don't usually make a COM interface classes for private modules just to reduce code dependency. |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| I suppose I still don't see the advantage of Pimpl. I'm not a C++ guru, but I am an enthusiast. Hey, if Stroustrup says to use abstract base classes, I think I'm gonna listen to him. HE is a C++ guru. From what I have read, one should write C++ and assume that the compiler can do its job. I also don't see why ABCs cause a full recompilation. You put the ABC in one header file. This is included in any modules that need to know about the ABC. You don't worry yet about the implementation. Who cares? |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| The article is full of errors. E.g. it claims that you can't use std::auto_ptr to hold the pointer. Of course you can. I do it all the time and it works just fine, thank you very much. An other error would be the name. It's short for "Pointer to Impl", nothing else. |
||||
|
||||
![]() Simagery Member since: 2/4/2000 From: Austin, TX, United States |
||||
|
|
||||
Quote: The problems with std::auto_ptr are well-documented. Of course, the problems nearly all stem from users mistaken assumption that the purpose of auto_ptr is to be a smart pointer. Well, it is... but it ain't that smart. For one, only one auto_ptr can owns a pointer at any one time, so doing something like this: MyPimplUsingClass something, another; something = another; Now you've confused things. The auto_ptr in something now has a valid pointer (which it took from another), while another now has a null value. Probably not what was intended. But exactly what auto_ptr is supposed to do, and I'm sure it's what the authoer was referring to. Quote: While we're nit-picking, wouldn't that be better stated as "Another error would be the name. It's short for 'Pointer to Implementation..." Whatever, that's certainly not official by any means. In fact, a quick Google for pimpl "private implementation" yields more results (~1000) than pimpl "pointer to implementation" (~130) plus pimpl "pointer implementation" (~340). I'll happily admit that many of the first query are not defining the abbreviation, but enough of them are to diffuse that as an "error" in the article. I'll not pretend the article was gloriously in-depth, but Pimpl is pretty simple ( ). |
||||
|
||||
All times are ET (US)![]() |
Last Thread Next Thread ![]() |
|