Completely hiding the private parts of a class

I wonder if it is possible to completely hide the private declaration of a class so that the details do not appear in the .h file?

If not, is there any work-around using multiple inheritance, preprocessors, or some hacks along the line in order to achieve the same effect?

It is bugging me...people *always* make assumptions about the implementation details of my classes from the .h files.
wy2lamAsked:
Who is Participating?
 
WynConnect With a Mentor Commented:
How about this?
0
 
bbousquetCommented:
You can use an abstract base class and just derive your 'private' class from it - then you just give out the base class .h.
0
 
WynCommented:
->I wonder if it is possible to completely hide the private declaration of a class so that the details do not appear in the .h file?
================

One hint:

The data hidden is aimed at code,not programmer.Since it's in private part.It's hidden perfectly.


If you want to hide data to the programmer,simply mimic the way COM/DCOM behaves:
Give only the virtual functions part to the user.And let them use it through the vtable.  


Another hint:
You cannot apply this way on youself(offeror part).
If the compiler doesnt know the declaration of a class.How it allocate memory?

Regards
W.Yinan
0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

 
wy2lamAuthor Commented:
A very good comment, however, I'm rejecting it as an answer because:

1. Theoretically, data hidden is aimed at code, but the fact that the programmer can see it can create some problems, e.g. making runtime assumptions like "I can see an array in your private declaration, so your class must take constant time to do look-ups!"

2. So I have to distinguish which .h file is a candidate to give out and which not to.  But what I want to do is just cut the private parts off ALL the .h files if possible... (say, for simplicity assume all .h files are visible and all .cc files are invisible, to the programmer, of course)

3. If I could put part of the declaration in the .cc file and part on the .h file, the compiler *can* still determine how to allocate memories - that is, if it is possible.

I just want to see if there's a way to make C++ codes look cleaner in a software engineering perspective.  I know it is not very practical but it looks better and cleaner that way...if C++ has something that approximates the opaque types in the Wirth language familiy (Modula-*, Oberon-*) then I'd be happy.
0
 
WynCommented:
Btw:
If you dont want to thoroughly mimic COM.You can create a static function to return a pointer to the class to the user.This static function simply create a instance of your class.

another approach is to use something like forward declaration:

Your part:
struct A
{ int a ;};

class xx
{A* pa;
//.......
 public:
 void initial(){
 pa = (a*)malloc(sizeof(a));
 a->i = 0;
}
}

User part you give the .h:

class xx
{struct A;
 A* pa;
//.......
 public:
 void initial();
}

By calling initial first,this way you hide the a member of pa;
like(user part):

xx myx;
myx.initial();
//.....

Regards
W.Yinan
0
 
WynCommented:
wow ,I'm rejected when I'm elaborating my answer:)
0
 
WynCommented:
A makeup:
In above code,you can put all private part(data) in that struct and it's hidden from the user.They cannot find the declaration.
0
 
RONSLOWCommented:
This method is the "cheshire cat" method.  The point to the implementation is called a "pimple".

Quite a common C++ technique.


0
 
nietodCommented:
>> 2. So I have to distinguish which .h file is a
>> candidate to give out and which not to.  But
>> what I want to do is just cut
>> the private parts off ALL the .h files if possible...
>> (say, for simplicity assume all .h files are visible
>> and all .cc files are
>> invisible, to the programmer, of course)

In general this is not safe.  (there are ways to make it safe, but it isn't always safe.)  For example if you have a class like

class A
{
private:
   int Prv;
public:
   int Pub;
   A();
};

You you could try giving the client a class def like

class A
{
public
    int Pub;
    A();
};

and a library file that contains the constructor you write for A (that is, A()).

but that won't work.  When the client's code goes to create an A object it will create a object that is too small, it doesn't store enough room for the Prv data member, so the constructor for A will probably crash (somethign somewhere will probably crash.   One way around this is to make the class def you give the client have unidentified data storage space.  Like use a char array that is the same size as the space used for all the private data members.  Like

class A
{
private;
   char Reserved[4];
public:
   int Pub;
   A();
};

This requires that you know exactly how the compiler will lay out an object, so it certainly is not portable and really isn't highly recommended.

A better idea is to use the C++ language features to do this.  You can make a class that declares the public interface and public data members you want the client to have.  And give this class a protected constructor so that it cannot be created by the client (also give it a virtual destructor).  Then derive a class from this class that contains the private data members and functions and other implimentation details.  Do not give the client this class.  You also have to give the client a function that returns a pointer to a dynamically created (new) object.  The pointer's type will be a pointer to the base class (the type the client knows about), but the object will actually the derived type.  For example,

class Base
{
protected:
   Base(); // No creation by mistake.
public:
   int Pub;
   virtual ~Base();
   static Base *CreateBase(); // creation function.
};

class Derived : public Base // Not for client's eyes.
{
  int Prv;
};

// in a .lib or DLL given to the client
static Base *Base::CreateBase()
{
   return new Derived;
};
0
 
WynCommented:
Hmm... dont know this way to call it because here non-book written in English.
0
 
RONSLOWCommented:
nietod's answer is basically what bbousquet and wyn said.  It is similar in concept to what COM does.

The cheshire cat is a little simpler.

A problem with the ABC method of nietod's above comes if/when you need to derive a new classes.

Lets say you want to derive a publicly visible class from Base above (calls it BaseEx.  The implementation would (most likely) also be derived from Derived (call it DerivedEx), but must also be derived from BaseEx. ie

// publicly visible
class Base {...};
class BaseEx : public Base {...};

// hidden implementaion
class Derived : public Base {...};
class DerivedEx : ??? {...};

How do you declare DerivedEx ??
0
 
WynCommented:
->You also have to give the client a function that returns a pointer to a dynamically created (new) object.  The pointer's type will be a pointer to the base class (the type the client knows about), but the object will actually the derived type.  
===================
Aint this COM doing? :)
All in all ,I think the way as I have mentioned in my first comment:mimic how COM do.or use cheshire cat way as I code above(I just learned).
I think they are somewhat common to certain degree.
0
 
nietodCommented:
>> nietod's answer is basically what
>> bbousquet and wyn said
Yes, more-or-less, I had originally planned to say that, but it got lost in the momentum.

>> Aint this COM doing? :)
COM can be viewed as a special case of this design.  A case where all functions are virtual and there are no public data members.   In this more generalized case the base class can be used an ordinary C++ base class with non-virtual functions, public data members, operator overloading etc.  COM is much more restricted, but still has the same core design.
0
 
wy2lamAuthor Commented:
Wyn and nietod, good approaches, but I guess I somehow mispresented what I am trying to do - basically, people will have access to all the source code, so no .lib or .dll is distributed.  Just a nice, clean way to cut the private parts off the .h files is enough.  (assumption: people won't snoop your .cc files but they'll assume everything they can see in the .h files.  All files will be given to them).

So, maintaining two versions of essentially the same .h file is out of the question.

But I guess the second method will still work (I'm surprised how closely this resembles Modula-3's approach). I know other uses of a non-public constructors but I didn't know it can be used this way!!

So basically, if my guess is correct, the following is all I have to do: (?)
--------------------------------------
in a .h file, I'll put:
--------------------------------------
class PublicClass {
protected:
   PublicClass();
public:
   static PublicClass *Create();
   virtual ~PublicClass();
   virtual void OtherPublicStuffs();
};
--------------------------------------
in the corresponding .cc file,
--------------------------------------
class PrivatePart : public PublicClass {
   // private stuffs
};

static PublicClass *PublicClass::Create() {
   return new PrivatePart;
}
--------------------------------------

if it is similar to what COM does, I guess the points should go to Wyn, otherwise I guess to nietod...(well, the points are of no use anyway...it's the discussion that matters) but who should I give the points to?
0
 
wy2lamAuthor Commented:
I just tried it on gcc and it tells me there're undefined references (apart from the missing main() )

/tmp/ccH8ZVq5.o: In function `PrivatePart::PrivatePart(void)':
/tmp/ccH8ZVq5.o(.PrivatePart::gnu.linkonce.t.(void)+0x9): undefined reference to `PublicClass::PublicClass(void)'
/tmp/ccH8ZVq5.o(.PrivatePart::gnu.linkonce.t.(void)+0x2c): undefined reference to `PublicClass::~PublicClass(void)'
/tmp/ccH8ZVq5.o: In function `PrivatePart type_info function':
/tmp/ccH8ZVq5.o(.gnu.linkonce.t.__tf11PrivatePart+0xd): undefined reference to `PublicClass type_info function'
/tmp/ccH8ZVq5.o(.gnu.linkonce.t.__tf11PrivatePart+0x14): undefined reference to `PublicClass type_info node'
/tmp/ccH8ZVq5.o: In function `PrivatePart::~PrivatePart(void)':
/tmp/ccH8ZVq5.o(.gnu.linkonce.t._._11PrivatePart+0xe): undefined reference to `PublicClass::~PublicClass(void)'
collect2: ld returned 1 exit status

is there anything that can be done to make the linker happy?
0
 
bbousquetCommented:
wy2lam,

Please do NOT mention the words 'Modula-3'... it drives me mad ;-)
0
 
wy2lamAuthor Commented:
Nevermind - I forgot to define PublicClass() and ~PublicClass().

Now the code compiles and links.  Looks good to me.  Is there any catches?
0
 
wy2lamAuthor Commented:
bbousquet: How come?
0
 
bbousquetCommented:
I had to work with Modula-3 for a couple of months and I clearly hated it. It's too "Pascal-ish", syntaxically...

Don't get me wrong - it's not a bad language - it's just that I prefer C/C++ a million times over M3.

;-)
0
 
RONSLOWCommented:
The only catch is if you derive one of your publically derived classes from another.  How to define the implementation (private) class without duplicating data etc. is a problem.

The cheshire cat method doesn't have that problem, but you needto manually forward calls to the implementations.

0
 
nietodCommented:
>> Just a nice, clean way to cut the private parts
>>off the .h files is enough.

The method I illistrated (and others suggested) would work for this as well.  Just the hidden stuff either goes in a .h file that shoudl be ignored or in a section to be ignored or in a source code file that should be ignored.


>> /tmp/ccH8ZVq5.o(.PrivatePart::gnu.linkonce.t.
>> (void)+0x9): undefined reference to
>> `PublicClass::PublicClass(void)'
Sounds like you didn't write the PublicClass constructor. (you just declared it in the class).  You can place the definition in the class or on a source code file.

>> /tmp/ccH8ZVq5.o(.PrivatePart::gnu.linkonce.t.
>> (void)+0x2c): undefined reference to
>>`PublicClass::~PublicClass(void)'
Same thing, you need to define the destructor somewhere.

I think the problems will go away then.

>> The only catch is if you derive one of your
>> publically derived classes from another.
This is definitley true.  It is a problem only if you want to derive from a class, but even if you don't initially expect to derive from a class sometimes the need arrises.
0
 
wy2lamAuthor Commented:
Thanks everyone.

Both techniques looks good - with the cheshire cat approach a bit more flexible - I can see that they're two implementations of the same idea, one abuses OO and one does not...

By the way, I've dug up the Cheshire cat techniques from Thinking in C++...never know it has that, oh well.  Here's the link anyways.

http://codeguru.developer.com/cpp/tic/tic0067.shtml
0
 
RONSLOWCommented:
It always helps to know the right words to describe something .. makes it a lot easier to find info (such as the TIC info).  Unfortunately, with this one, you get lots of links to Alice In Wonderland :-).

Another key phrase to look for is "compilation firewalls".

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.