views:

205

answers:

5

Hi,

I would like to know if there is a way to put only protected and public stuff on the header file .h, and all private stuff in the compile unit .cpp I need this because the library is going to be used by others, and I wouldn't like to have to copy and edit all .h files to remove private declarations and implementations. I tried but got the duplicate declaration error

another question is about private static stuff can I declare them on the header file and implement them on the .cpp unit? a private variable and a public get method I tried but couldn't implement the method on the unit, it only worked with the declaration and implementation on the header

[]s, Joe

+22  A: 

The proper way to deal with this is to implement the pimpl idiom: Create a class or struct for all private data and put a pointer to such an object in the header file, together with a forward declaration. Now nothing of the private data and methods is visible from the header file.

andreas buykx
Here are also two good links:http://www.gotw.ca/gotw/024.htmhttp://www.gotw.ca/gotw/028.htm
jdehaan
Could someone explain this link:http://www.gotw.ca/gotw/028.htmI didn't understand how the Allocate and Decallocate functions are going to free and create the derived struct.Thanks!
Jonathan
A: 

Andreas has the answer but note that this will make your code somewhat more obtuse for yourself:

 // header file

 struct hidden_structure;

 class Foo {
     hidden_structure* hidden_data;
 public:
     Foo();
     ~Foo();

     void doStuff();
 };

 // your cpp file

 struct hidden_structure;
     int stuff;
     hidden_structure() : stuff(0) {}
 }

 Foo::Foo() : hidden_data(new hidden_structure) {}
 Foo::~Foo() { delete hidden_data; }

 void Foo::doStuff() { hidden_data->stuff += 34; } // hey, it does a lot of stuff

As you can see, the more data inside hidden_structure the more complex this can become.

jmucchiello
1) Use a smart pointer, 2) what do you mean by "the more data, the more complex"? the complexity is constant (you just have to precede every field reference with `p->` or whatever the pimpl field is called).
Pavel Minaev
that kind of code seems kinda ugly.I guess I will have to do this PIMPLor should I delete all below private: before handling it to someone? :(I waste the same time coding and designing my code.does that happens to you too?
Jonathan
A: 

Same as John's code, but I am using a pointer instead of references:

// file.h
class TheClass_p;
class TheClass{
  public: 
    TheClass();
    ~TheClass();
  private
    TheClass_p *d;

};

// file.cpp
class TheClass_p {
  int foo;
  float: bar;
};

TheClass::TheClass(){
   d = new TheClass_p;
}

TheClass::~TheClass(){
   delete d;
}

Edit: added destructor to free a memory leak

elcuco
... and leak memory.
Pavel Minaev
You need to free the memory in the destructor.
Vitali
+5  A: 

The correct answer to this is to use a Pimpl (via a pointer, as Pavel points out). There's also a crazy but potentially correct way described in Matthew Wilson's Imperfect C++, where you can forward declare an internal structure and include an opaque block of memory in your class, and then in-place construct the internal structure (whose definition is made in the implementation file) in the main class constructor in the implementation file.

I should point out that Wilson shows this in an appendix where he confesses to several such "crimes against programming" as a caution to programmers trying to be too clever. He says, and I say, that you shouldn't use this. However, if you have some overriding exacting performance requirements it's possible that it might be of some use.

dcw
Preferably a smart pointer, in fact - `const std::auto_ptr<T>` is perfect for this.
Pavel Minaev
Also, the problem with the trick you describe (of preallocating a block within the object itself, rather than a pointer) is that it kills one other advantage pimpl offers, which is usually more important than hiding private members - it lets you write versioning-safe code without restrictions on new fields (since they all go to the private object). For cases where perf is actually important enough that this is an issue, enforcing encapsulation is probably even less of a concern, so just do it "normally".
Pavel Minaev
Pavel, you're right (on the versioning). As I hope I strongly imparted, neither I nor Wilson's book advocate this technique. It's just that (as seems to always be the case in C++), there are a very few circumstances where it might be a reasonable choice. Buyer beware! :-)
dcw
A: 

Couldn't you declare the full class name for users, but put a class definition in the .h file that includes only the publics and privates, then in the .cpp file subclass from the public definition, and define only privates?

Like this:

.h file--

class useThis;   // users actually use this class

class publics {  //this is the interface they see
public:
    int foo;
};

.cpp file--

#include "foo.h"

class useThis: publics {

private:
    void add(int b);

};

void useThis::add( int b )
{
    foo+= b;
}
tod frye
I don't think this works. When people are using the header, there is nothing to tie `useThis` to `publics`.
Jonathan Leffler
i am pretty sure it does work.everything in publics is also in useThis, as useThis inherits from publics.
tod frye
this works or not?it seem a good way to even use with templates
Jonathan