Solved

Completely hiding the private parts of a class

Posted on 2000-02-25
23
297 Views
Last Modified: 2010-04-02
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.
0
Comment
Question by:wy2lam
  • 7
  • 6
  • 4
  • +2
23 Comments
 
LVL 2

Expert Comment

by:bbousquet
ID: 2560607
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
 
LVL 5

Expert Comment

by:Wyn
ID: 2560668
->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
 

Author Comment

by:wy2lam
ID: 2560690
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
 
LVL 5

Expert Comment

by:Wyn
ID: 2560693
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
 
LVL 5

Expert Comment

by:Wyn
ID: 2560695
wow ,I'm rejected when I'm elaborating my answer:)
0
 
LVL 5

Accepted Solution

by:
Wyn earned 150 total points
ID: 2560696
How about this?
0
 
LVL 5

Expert Comment

by:Wyn
ID: 2560749
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
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2560808
This method is the "cheshire cat" method.  The point to the implementation is called a "pimple".

Quite a common C++ technique.


0
 
LVL 22

Expert Comment

by:nietod
ID: 2560844
>> 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
 
LVL 5

Expert Comment

by:Wyn
ID: 2560848
Hmm... dont know this way to call it because here non-book written in English.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2560854
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
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 5

Expert Comment

by:Wyn
ID: 2560863
->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
 
LVL 22

Expert Comment

by:nietod
ID: 2560876
>> 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
 

Author Comment

by:wy2lam
ID: 2561681
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
 

Author Comment

by:wy2lam
ID: 2561693
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
 
LVL 2

Expert Comment

by:bbousquet
ID: 2561702
wy2lam,

Please do NOT mention the words 'Modula-3'... it drives me mad ;-)
0
 

Author Comment

by:wy2lam
ID: 2561705
Nevermind - I forgot to define PublicClass() and ~PublicClass().

Now the code compiles and links.  Looks good to me.  Is there any catches?
0
 

Author Comment

by:wy2lam
ID: 2561707
bbousquet: How come?
0
 
LVL 2

Expert Comment

by:bbousquet
ID: 2561724
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
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2561793
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
 
LVL 22

Expert Comment

by:nietod
ID: 2561902
>> 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
 

Author Comment

by:wy2lam
ID: 2561904
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
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2561920
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

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now