Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a class be private to a translation unit?

Consider the following code:

/*
 * myclass.h
 */

class myclass_impl
{
    // ...
}

boost::shared_ptr<myclass_impl> myclass;

Can I somehow make myclass_impl (or, at least, the direct use of it) be private to the translation unit it is defined in, allowing clients to only use the myclass typedef? What I am trying to achieve is have the compiler alert me if somebody uses the implementation class directly.

like image 519
Dan Nestor Avatar asked Nov 25 '11 13:11

Dan Nestor


2 Answers

Declare your class in the source file (not header file) and it will not be accessible from other translation units. Then, use forward declaration to declare a pointer/reference in your header file.

Or define a impl header file and comment that it should not be included in other source files.

/*
 * myclass.h
 */

class myclass_impl;

class myclass
{
  boost::shared_ptr<myclass_impl> myclass_i;
public:
  myclass() : myclass_i(new myclass_impl) { }
  int getI() const;
};


/*
 * myclass.cpp
 */

class myclass_impl
{
  int i;
public:
  myclass_impl() : i(4) { }
  int getI() const { return i; }  
};

int myclass::getI() const 
{ 
  return myclass_i->getI(); 
}
like image 141
stefaanv Avatar answered Oct 18 '22 06:10

stefaanv


You can create interface myclass and use factory method to provide instances of you private class myclass_impl defined in anonymous namespace in same file with method. Other variant is pimpl.

File myclass.h

class myclass
{
public:
    virtual void doSomething() = 0;
    static boost::shared_ptr<myclass> createInstance();
};

File myclass_impl.cpp

#include "myclass.h"
namespace {
    class myclass_impl : public myclass
    {
    public:
        virtual void doSomething() { std::cerr << "Hi there" << std::endl; }
    };
}
static boost::shared_ptr<myclass> myclass::createInstance()
{
    return new myclass_impl();
}

Update (added totally awful solution):

myclass.h

class destroyable { virtual ~destroyable() {} };
class myclass {
private:
    boost::shared_ptr<destroyable> pimpl;
public:
    void doSomething();
};

myclass_impl.cpp

namespace {
    class myclass_impl : public destroyable {
    public:
        void doSomething() { /* ... */ }
    };
}
void myclass::doSomething() { static_pointer_cast<myclass>(pimpl)->doSomething(); }
like image 26
ony Avatar answered Oct 18 '22 06:10

ony