11

I have written a library (doesn't matter what it does), which obviously has its header file. Now, I want to hide private elements of that header file, so if I provide my library to somebody, he/she should only see public members (preferably no class definition, nothing other than function definitions). One way would be creating C-style header, which will contain some kind of "init" method which will be used to create an instance of the actual class of library and the user will have to pass a pointer of that object to every function to do the job.

Is it a good practice?

Are there any other publicly accepted ways of doing something like that?

Thanks in advance.

khajvah
  • 4,889
  • 9
  • 41
  • 63
  • 2
    Looks like you could use the Pimpl idiom. But whatever method you use in the end, you need to be aware that hiding the implementation can have performance issues (the compiler won't be able to inline much). – syam Jul 09 '13 at 17:34

6 Answers6

16

In addition to the Factory pattern (which, in my opinion, can become unwieldy), you can also hide your private members behind a PIMPL (Pointer to IMPLementation):

// Interface.hpp
class Implementation;
class Interface {
public:
    Interface() : pimpl(new Implementation()) {}
    void publicMethod();
private:
    std::unique_ptr<Implementation> pimpl;
};

// Interface.cpp
class Implementation {
public:
    void PrivateMember();
};

void Interface::publicMethod() { pimpl->PrivateMember(); }

This has the advantage of hiding implementation, at the cost of a single pointer indirection, not much different from the typical inheritance-based Factory pattern.

This can also be ABI stable. Changes to your implementation won't affect linkage, since no changes will ever be visible to the rest of the program. This is a good pattern to use when implementing shared objects, for example.

It's also a common C++ idiom, so other C++ programmers will recognize it without question.

In the case of a class which will follow the Singleton pattern, you can avoid exposing the PIMPL at all, and simply write the entire implementation in an anonymous namespace in your .cpp file, where you can put as much state and private functions as you wish, without even hinting at it in your interface.

greyfade
  • 24,948
  • 7
  • 64
  • 80
6

You can create a publicly-visible interface. Create an abstract class with the functions you want to expose, then have your implementation extend it.

For example, an interface:

class Interface {
public:
    virtual void publicMethod() = 0;
...
};

And the implementation:

class Implementation : Interface {
public:
    virtual void publicMethod();
private:
    int hiddenMethod();
};

Then you only export the symbols for Interface. Now, in order for the user of the library to get instances of Interface which are actually Implementations, you need to provide a factory:

class Factory {
public:
    //can create and return an Implementation pointer, but caller will get an Interface pointer
    std::shared_ptr<Interface> getImplementationInstance();
}
Eric Finn
  • 8,629
  • 3
  • 33
  • 42
  • Ok, let's say I am a user of that interface. So, I create an instance of class Interface, then call functions BUT how will it know that I am calling methonds of Implementation class (as we have created only instance of Interface) – khajvah Jul 09 '13 at 17:39
  • @khajvah you don't need to know. But the interface should provide you with a means to instantiate different implementations and give you back a smart pointer to the abstract base type. – juanchopanza Jul 09 '13 at 17:40
  • Neat! This completely hide the implementation, I think it could be better to set interface class as an abstract class – Charles Chow Sep 25 '14 at 01:08
  • @CharlesChow Good catch, I forgot to make the virtual member function pure virtual. – Eric Finn Sep 25 '14 at 12:37
5

Base on Eric Finn's answer, you can just declare an interface class to hold all your public methods which considered to be your API, and hide all implementations and private members/methods in implementation class which inherits interface class, here's the example:

Your header file: my_api.h

// your API in header file
// my_api.h
class interface {
public:
    static interface* CreateInstance();
    virtual void draw() = 0;
    virtual void set(int) = 0;
};

your implementation(shared library): my_api.cpp (users won't see this when you make it a shared library) So you can hide all your implementation and private methods/members here

#include "my_api.h"
        // implementation -> in .cc file
class implementation : public interface {
    int private_int_;
    void ReportValue_();
public:
    implementation();
    void draw();
    void set(int new_int);
};

implementation::implementation() {
    // your actual constructor goes here
}

void implementation::draw() {
    cout << "Implementation class draws something" << endl;
    ReportValue_();
}

void implementation::ReportValue_() {
    cout << "Private value is: " << private_int_ << endl;
}
void implementation::set(int new_int) {
    private_int_ = new_int;
}
interface* interface::CreateInstance() {
    return new implementation;
}

How user uses your API:

#include <iostream>
#include "my_api.h"

int main(int argc, const char * argv[])
{

    using namespace std;
    interface* a; interface* b;
    a = interface::CreateInstance();
    a->set(1);
    b = interface::CreateInstance();
    b->set(2);
    b->draw();
    a->draw();
    return 0;
}

Output:

Implementation class draws
Private int is: 2
Implementation class draws
Private int is: 1    

In this pattern, your api is just an abstract class which works like a factory, you can also implement the virtual method in different classes and specify which instance you would like to call.

Community
  • 1
  • 1
Charles Chow
  • 575
  • 1
  • 8
  • 12
1

I think you need to create Dynamic Link Library (dll).

Please take a quick look at this link:

Rm ko
  • 49
  • 6
  • Thanks for the answer. The problem is that I am a linux user and I do not think there is a way to create a dll in linux. What are the alternatives? – khajvah Jul 09 '13 at 17:33
  • 1
    Actually, I have no idea about linux. but i found this answer close to yours... Hope it helps! http://stackoverflow.com/questions/206272/hiding-private-data-members-c – Rm ko Jul 09 '13 at 17:36
  • Thanks, I will look at those idioms :) – khajvah Jul 09 '13 at 17:40
  • 1
    @khajvah Dlls exist in linux under the name "shared object" – Mooing Duck Jul 09 '13 at 17:44
  • 2
    I don't see why a shared library would solve his problem. Can you elaborate please? – Korchkidu Jul 09 '13 at 18:09
  • The author wants to create a shared library and his question is he wants to hide all private members and the implementations – Charles Chow Sep 25 '14 at 01:33
0

You might want to take a look at the envelope/letter idiom, bridge design pattern, or proxy pattern. Basically, you would create an outer (public) class that would just forward your public method calls to the inner (private) class. Your InnerClass.h header only needs to be visible/known to your OuterClass.cpp and InnerClass.cpp source files.

Each of these patterns provides a mechanism of separating the implementation from the interface so that the caller is not coupled to the implementation. Sometimes this is desired to reduce compiler dependencies on large C++ projects. Another common reason for wanting to do this is just when you want to hide the implementation details so that the caller only sees a single opaque pointer.

=======  OuterClass.h =====
class InnerClass; // forward declaration is all that's needed

class OuterClass {
    private:
        InnerClass *pInner;

    public:
        InnerClass();

        bool doSomething();
};

======= OuterClass.cpp ======
#include "OuterClass.h"
#include "InnerClass.h"

OuterClass::OuterClass() : 
    pInner(new InnerClass())
{
}

bool OuterClass::doSomething()
{
    return pInner->doSomething();
}
Paul Dardeau
  • 2,589
  • 1
  • 13
  • 10
  • Can you expand on your answer? Your answer can be even more helpful if you add descriptions of these patterns, how they would be used, and your reasoning for suggesting them. – greyfade Jul 09 '13 at 17:54
  • This is a bad variation of the pimpl idiom – droptop Jan 15 '21 at 12:46
-1

There actually is a way to do this without having to use classes. I had the same issue and here is a very simple solution:

Just put your private things into the .cpp file. Your header file will look something like this:

// These will be visible to everyone using this library
void function();
int someNumber = 2;

and your .cpp file:

void function() {
    // whatever this function does
}
// This will be only visible to the library itself
static void secretFunction() {
    doSomeSecretStuff;
}

static int PIN = 1234;
// Okay, if you write this Number into your library and expect it to be safe,
// then screw you, but at least no one will be able to access it with code

When calling the "public" functions from outside you now don't need any instance of that class anymore: Just place the library in the correct directory and include it, but you probably have already taken care of that) and call the functions by their names in the Lib.h file. In the instance of this example it would look something like this:

#include "Lib.h"

int main(int argc, const char * argv[]) {
    function();
    return 0;
}

Thanks to Edgar Bonet for helping me find this solution on the Arduino Stackexchange!

LukasFun
  • 171
  • 1
  • 4
  • 17