Click here to Skip to main content
15,867,860 members
Articles / Programming Languages / C++

Hiding Implementation Details in C++

Rate me:
Please Sign up or sign in to vote.
3.88/5 (16 votes)
19 Sep 2009CPOL1 min read 77.5K   19   23
Get the implemention details out of the C++ include file

Introduction

I want to share a simple way of hiding implementation details in C++.

The Classic Way

A C++ class definition lets you control access to private data and methods while exposing a public interface to manipulate the data.

C++
// Define a public interface in foo.h
class Foo
{
public:
   Foo() {}
   void SetPosition(float x, float y);
private:
   float m_x, m_y;    	// private data
   void PrivateMethod() {}	// private method
};
C++
// Define a private implementation in foo.cpp
void Foo::SetPosition(float x, float y)
{
     m_x = x; m_y = y;
}

Problems...

While the code for the implementation is hidden in the CPP file, the encapsulation is incomplete because:

  1. private data members and methods are defined in the header file
  2. changing the implementation often requires changing the header file because
    • you add or change data members or
    • you add or change private methods

Ideally, the header file should be something you read to learn about the public interface for a class and nothing else.

Improved

To solve this problem, you can use inheritance.

C++
// Define a public interface in foo.h
class Foo
{
public:
   virtual void SetPosition(float x, float y) = 0;
   static Foo* Create();
protected:
   Foo() {}    // hide
};
C++
// Define a private implementation in foo.cpp
class FooImpl : public Foo
{
public:
   FooImpl() {}
   void SetPosition(float x, float y)
   {
        m_x = x; m_y = y;
   }
private:
   float m_x, m_y;   	// private data
   void PrivateMethod() {}	// private method
};

// Define factory method
Foo* Foo::Create()
{
    return new FooImpl();
}

The client no longer sees any of the implementation details. The cost is that we are now required to have a factory method and virtual methods.

Improved With No Virtual Methods

Adding virtual methods might not be acceptable if your class objects are streamed off disk (memory ready) or you don't want to incur the performance penalty. Here is a solution that works without virtual methods:

C++
// Define a public interface in foo.h
class Foo
{
public:
   void SetPosition(float x, float y);
   static Foo* Create();
protected:
   Foo() {}    // hide
};
C++
// Define a private implementation in foo.cpp
class FooImpl : public Foo
{
public:
   FooImpl() {}

   // allow Foo methods to see our private members
   float m_x, m_y;    	// private data
   void PrivateMethod() {}	// private method
};

// Define factory method
Foo* Foo::Create()
{
    return new FooImpl();
}

// downcasting methods
inline FooImpl * GetImpl(Foo* ptr) { return (FooImpl *)ptr; }
inline const FooImpl * GetImpl(const Foo* ptr) { return (const FooImpl *)ptr; }

// Define public method
void Foo::SetPosition(float x, float y)
{
    FooImpl * f = GetImpl(this);
    f->m_x = x; f->m_y = y;
}

By downcasting in the class methods, we get access to the implementation data without virtual methods.

Conclusion

This technique should probably not be used for small classes such as vectors, where hiding data members is not as important. In this situation, inline methods need access to the data in the header file. But any class that has a non-trivial data structure that might change would benefit from this way of insulating the header file from changes in the implementation.

History

  • Sep-2009: Article submitted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Buzz Monkey Software
United States United States
David McClurg is a game programmer from Oregon, USA. He is currently interested in C#, xna for zune, and steering behaviors. When not coding, David enjoys tennis, kayaking, and botany.

Comments and Discussions

 
QuestionHow to hide foo.cpp? Pin
BekirSait31-Jan-19 20:26
BekirSait31-Jan-19 20:26 
GeneralMy vote of 1 Pin
Joe Sonderegger16-Dec-09 21:53
Joe Sonderegger16-Dec-09 21:53 
GeneralOne of the benefits you cite is non-existent (potentially worse) Pin
LKarayan1-Oct-09 7:49
LKarayan1-Oct-09 7:49 
GeneralMy vote of 2 Pin
bobyx8225-Sep-09 9:08
bobyx8225-Sep-09 9:08 
GeneralI liked it Pin
Grump24-Sep-09 4:17
Grump24-Sep-09 4:17 
GeneralSimple, but nice idea Pin
csantia6623-Sep-09 22:33
csantia6623-Sep-09 22:33 
GeneralGood idea to implement interface using Mix-in class, without virtual functions Pin
Tage Lejon22-Sep-09 3:38
Tage Lejon22-Sep-09 3:38 
GeneralMemory leak! Pin
SergV-SNV21-Sep-09 16:55
SergV-SNV21-Sep-09 16:55 
GeneralRe: Memory leak! Pin
milkplus22-Sep-09 8:14
milkplus22-Sep-09 8:14 
GeneralRecommended book Pin
SergV-SNV22-Sep-09 16:41
SergV-SNV22-Sep-09 16:41 
GeneralQuestion is why Pin
Bob100021-Sep-09 4:35
professionalBob100021-Sep-09 4:35 
GeneralRe: Question is why Pin
RealSkydiver22-Sep-09 9:52
RealSkydiver22-Sep-09 9:52 
GeneralSorry, but not my solution Pin
Zaibot21-Sep-09 3:53
Zaibot21-Sep-09 3:53 
GeneralRe: Sorry, but not my solution Pin
milkplus21-Sep-09 8:27
milkplus21-Sep-09 8:27 
GeneralRe: Sorry, but not my solution Pin
Zaibot22-Sep-09 1:35
Zaibot22-Sep-09 1:35 
GeneralMy vote of 2 Pin
KarstenK20-Sep-09 21:22
mveKarstenK20-Sep-09 21:22 
GeneralRe: My vote of 2 Pin
Rick York22-Sep-09 10:06
mveRick York22-Sep-09 10:06 
GeneralpImpl Pin
PsiY19-Sep-09 22:48
PsiY19-Sep-09 22:48 
GeneralRe: pImpl Pin
milkplus20-Sep-09 18:01
milkplus20-Sep-09 18:01 
GeneralRe: pImpl Pin
Stefan_Lang22-Sep-09 22:40
Stefan_Lang22-Sep-09 22:40 
Generalsuggests Pin
cooolcode19-Sep-09 4:37
cooolcode19-Sep-09 4:37 
GeneralRe: suggests Pin
milkplus19-Sep-09 5:56
milkplus19-Sep-09 5:56 
Yes, this technique would only be good for sealed classes where you want to insulate the implementation details completely. No further inheritance would be possible. That's not so bad however. In Scott Meyer´s first "effective c++" book, he argues that in many cases composition is better than inheritance. For one thing, it gives you more control over what methods you want to forward. Inheritance is a high tension and tightly coupled relationship that often makes a complex system hard to maintain.

In a game engine, you have major subsystems-- audio, graphics, input, spots, physics, etc-- and each subsystem is fairly complex. If you can get all the implementation details out of the public interface, then you have a better chance of keeping them de-coupled. That's where I was coming from with this.
GeneralRe: suggests Pin
cooolcode20-Sep-09 1:32
cooolcode20-Sep-09 1:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.