Re: Can you help me summarize all the bad things with global variables?
On 11 sept, 09:18, Goran <goran.pu...@gmail.com> wrote:
On Sep 11, 12:00 am, =D6=F6 Tiib <oot...@hot.ee> wrote:
*.h
struct opaque_type_ref {};
void api(opaque_type_ref&, params); // rinse, repeat
*.cpp
namespace // implementation
{
class type : public opaque_type_ref
{
void api(params)
{
// "no this->" zone here.
}
}
type& impl(opaque_type_ref& obj) { return static_cast<type&>(obj);=
}
}
void api(opaque_type_ref& obj, params)
{
impl(obj).api(params);
}
This example does not solve the major inconvenience of such opaque
pointer style information hiding in general case of C++ class. Pimpl
has to be usually used because in C++ you often want to let the users
to derive from a class (if it hides its internals using compilation
firewall or not does not really matter)... and that means you have to
make virtual interface and protected interface visible.
That doesn't sound right. Pimpl is there exactly because you want to
hide the implementation completely. It kinda implies well separated
server and client roles.
Pimpl is there for private information hiding. The effect is also in
compilation times. It is because when you do not expose private
dependencies, relations, components then only .cpp needs to be rebuilt
if something changes there.
Everything else remains like usual. You still have a class. It still
has member functions, these may be virtual or protected. You may
freely derive from that class, if you need polymorphism. What is
private is not a business of derived classes as well as anyone else.
What is the user supposed to derive from? Implementation or exposed
pimpl holder class?
It is not "pimpl holder" class. It is a class with private information
hidden with compilation firewall. You can use that pimpl idiom with
every class. It involves slight performance hit (indirection and
dynamic allocation), but since most classes do not participate in
performance-critical processing you can pimpl almost everything. Often
it is done with every class exposed in module interface that is not
meant as abstract interface. Like BGB say else thread ... in good C
interface you do the same, expose only handles, interface functions
and callbacks (or virtual functions).
If implementation, what's the purpose of hiding it then? If the
purpose is to have hidden implementation _and_ extension points, isn't
it better to create extension points, instead of hiding implementation
with one hand, and exposing it with the other?
That is implementation detail. That pimpl may well be polymorphic
pointer. You often have to expose things internally in your module
that you do not want to expose externally.
Deriving from holder, OTOH, goes into "prefer containment to
inheritance" rule of thumb. Sure, user can do it, but only to make
holder's public interface bigger, not to change the behavior (pimpl
holder should not have any virtual functions anyhow).
This is not true. Why it may not have virtual functions? Why it may be
not used as base class? I see no reasons. It may have logical
restrictions but if there are restrictions then such have to be
documented as comments in interface. It should not compile or should
assert or throw when interface restrictions are violated. Otherwise it
is completely normal class for its users, useful as a base class,
container element or data member. Pimpl idiom does not put any
restrictions there. The benefits of having C++ interface remain too
few if you get rid of inheritance and polymorphism.
I somehow think, you are making things more complicated than they
should be.
Me? :) I somehow feel that you oversimplify. Information hiding
actually makes things for everybody less complicated. It first seems a
overhead when you have less than 100 000 lines of code in product. No
product ever stays there. Either it loses competition or customers
like it. If it wins then it starts to sell and grow and expand.
Average successful project has up to 50 modules but i have lately
participated in projects with hundreds of modules. Every evidence
shows (like histories of version control, release notes and issue
trackers) that the modules with clear interface are more immune to
ravages of time. Strict interface allows better and more reliable set
of unit tests and carefully hidden internals leak less and cause less
complications. Lot of popular libraries out there use pimpl therefore
massively.
If you do not want C++ interface (that has inheritance and
polymorphism) then it may be is reasonable to use C interface (that is
de facto language-neutral), other language-neutral interface (like
COM) or even both platform and language-neutral interface (like
CORBA).