Encapsulation (information hiding) is a very useful concept, ensuring that only the barest minimal details are published in the API of a class.
But I can't help thinking that the way C++ does this is a little deficient. Take, for example, a (Celsius-based) temperature class like:
class tTemp {
private:
double temp;
double tempF (double);
public:
tTemp ();
~tTemp ();
setTemp (double);
double getTemp ();
double getTempF ();
};
Now, that's a very simple case but it illustrates a point that the encapsulation isn't perfect. "Real" encapsulation would hide all unnecessary information such as:
temp
variable (and its type).So, ideally, it seems to me that the implementor of the class would use the above header but any client of the class would see just the public bits.
Don't get me wrong, I'm not criticising C++ since it meets the stated purpose of preventing clients from using the private bits but, for more complex classes, you could easily work out internal details based on the names, types and signatures of private data and functions.
How does C++ allow implementors to hide this information (assuming it is possible)? In C, I'd simply use an opaque type so that the internal details would be hidden but how would you do that in C++?
I suppose I could maintain an separate class, totally hidden from the client and known only to my own code, and then keep an instance of it with a void *
in the visible class (casting within my code), but that seems a rather painful process. Is there an easier way in C++ to achieve the same end?
C++ uses an idiom known as "pimpl" (private implementation / pointer to implementation) to hide implementation details. Take a look at this MSDN article for details.
In short, you expose your interface in a header file as normal. Let's use your code as an example:
tTemp.h
class tTemp {
private:
class ttemp_impl; // forward declare the implementation class
std::unique_ptr<ttemp_impl> pimpl;
public:
tTemp ();
~tTemp ();
setTemp (double);
double getTemp (void);
double getTempF (void);
};
The public interface remains, but the private internals have been replaced with a smart pointer to a private implementation class. This implementation class is located only in the header's corresponding .cpp file, it is not exposed publicly.
tTemp.cpp
class tTemp::ttemp_impl
{
// put your implementation details here
}
// use the pimpl as necessary from the public interface
// be sure to initialize the pimpl!
tTtemp::tTemp() : pimpl(new ttemp_impl) {}
This also has the added advantage of allowing you to change the internals of your class without changing the header, which means less recompiling for users of your class.
For a full solution as shown in paxdiablo's pre-C++11 answer, but with unique_ptr
instead of void *
, you can use the following. First ttemp.h
:
#include <memory>
class tTemp {
public:
tTemp();
~tTemp();
void setTemp(double);
double getTemp (void);
double getTempF (void);
private:
class impl;
std::unique_ptr<impl> pimpl;
};
Next, the "hidden" implementation in ttemp.cpp
:
#include "ttemp.h"
struct tTemp::impl {
double temp;
impl() { temp = 0; };
double tempF (void) { return temp * 9 / 5 + 32; };
};
tTemp::tTemp() : pimpl (new tTemp::impl()) {};
tTemp::~tTemp() {}
void tTemp::setTemp (double t) { pimpl->temp = t; }
double tTemp::getTemp (void) { return pimpl->temp; }
double tTemp::getTempF (void) { return pimpl->tempF(); }
And, finally, ttemp_test.cpp
:
#include <iostream>
#include <cstdlib>
#include "ttemp.h"
int main (void) {
tTemp t;
std::cout << t.getTemp() << "C is " << t.getTempF() << "F\n";
return 0;
}
And, like paxdiablo's solution, the output is:
0C is 32F
with the added advantage of more type safety. This answer is the ideal solution for C++11, see paxdiablo's answer if your compiler is pre-C++11.