Sign in to follow this  
Deyja

Conflicting design goals

Recommended Posts

Deyja    920
...are causing me a bit of frustration. First, let me tell you microsoft really sucker punched me today. This morning, VSExpress politly informed me that the beta period had expired and to please stop using the software. Naturally, it doesn't give me a choice. Intalling beta2 was needlessly complicated by their dire warnings of doom if you failed to unistall everything else first. And then, I had to recompile boost. Finally, after a solid four hours, I was ready to tackle the problem I had meant to spent maybe half an hour on today. I have two goals which have nicely trumped each other. I want a clean, simple interface, and I want to hide the implementation completly. It's best illustrated by example;

header:

class A
{
public:
  void foo();

  void bar();
};

void dostuff(A* a);

cpp:

void somefunc(A* a)
{
  a->bar();
}

void dostuff(A* a)
{
  somefunc(a);
}

As you can see, only the function hidden in the cpp file uses A::bar. The problem is, anyone else can use A::bar too. Furthermore, somefunc must not appear in the header file, so I can not declare it as a friend to A. A::foo is the only public interface that should be visible out client code. Additionally, the usage must be as simple as A a; dostuff(a);. Currently, I just have A::bar dangling out there for anyone to call. The only way I see around it is to have somefunc exposed instead, which is an equally unappealing situtation. Or to change the way the class is used, which is absolutly out of the question.

Share this post


Link to post
Share on other sites
Andrew Russell    1394
I'm not to fond of your second design goal in the first place (first design goal is awesome). The second goal is really the source of your problem. The only real way to achieve it is to go all-out with a PIMPL (and here), or pure-virtual, or pure-C interface. It's not really something that works if you try and do it all within the one implementation class. C++ simply isn't designed to do 100% private implementations (although it can be made to with one of the above methods).

My suggestion: code by the first design goal - it is a good one, and then (by the laws of Yag Ni) add your total-implementation-hiding "stuff" only once you have a real need for it (and in that case, do it properly and seperatly).

Share this post


Link to post
Share on other sites
JohnBolton    1372
Take a look at the Bridge pattern -- that's what you are looking for. (PIMPL is one implementation). Like Andrew Russell, I recommend that you use it only if absolutely necessary. It will make your code much more complicated and cumbersome.

Generally, PIMPL is done like this:

A.h

class A
{
class Impl; // Forward declaration of implementation class
Impl * pImpl; // Pointer to implementation class

public:
A();
~A();

void dostuff();
};


A.cpp

class A::Impl
{
public:
void dostuff();
private:
void foo();
void bar();
};

void A::Impl::dostuff()
{
bar();
}

A::A() : pImpl( new A::Impl )
{
}

A::~A()
{
delete pImpl;
}

void A::dostuff()
{
pImpl->dostuff();
}

Share this post


Link to post
Share on other sites
rKallmeyer    396
I've seen this before and I like it:

In "Foo.h":

class Foo
{
public:
// Factory Constructor
static Foo* Create (/* create params */);

// Interface Methods
virtual void foo () =0;
};




In "FooImp.h":

class FooImp : public Foo
{
public:
virtual void foo ();
};

void dostuff ();




In "Foo.cpp":

#include "FooImp.h"

Foo* Foo::Create ()
{
return new FooImp ();
}




In "FooImp.cpp":

#include "FooImp.h"

void FooImp::foo ()
{
dostuff ();
}




Doing it like this addes a few extra source files too the project but I would generally use this layout in a place where it made sense to put several of these base/interface classes into a single file.

[edit - forgot to add "dostuff ()"]

Share this post


Link to post
Share on other sites
Deyja    920
Quote:
Generally, PIMPL is done like this:


I'm well aware of what the pimple pattern is; but thank you. It's nice when people put in effort.

Quote:
100% private implementations


Visible is fine. Anyone can just look at the source anyway. Unacessible is the real goal. If it's hidden behind something as simple as a private specification, anyone who wants to screw with it will have to go out of their way to do so. And if they screw it up then, it's their own fault.

Nuget5555; that create function and dynamic allocation really kill it.

Share this post


Link to post
Share on other sites
Andrew Russell    1394
Quote:
Original post by Deyja
Visible is fine. Anyone can just look at the source anyway. Unacessible is the real goal. If it's hidden behind something as simple as a private specification, anyone who wants to screw with it will have to go out of their way to do so. And if they screw it up then, it's their own fault.

So, uhmn, why don't you just make the functions private, possibly static, members (including dostuff and somefunc)?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this