Consider these two classes that employ the Pimpl idiom:
ClassA: Pimpl class forward declaration and variable declaration on separate lines
ClassA.h:
#include <memory>
class ClassA {
public:
ClassA();
~ClassA();
void SetValue( int value );
int GetValue() const;
private:
class ClassA_Impl;
// ^^^^^^^^^^^^^^ class forward declaration on its own line
std::unique_ptr<ClassA_Impl> m_pImpl;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variable declaration on its own line
//EDIT:
//Even if we use a raw pointer instead of a smart pointer,
//i.e. instead of declaring the smart pointer above, if we declare:
ClassA_Impl *m_pImpl;
//the situation in the *.cpp files and my questions (below) are the same.
};
ClassA.cpp:
#include "ClassA.h"
class ClassA::ClassA_Impl {
public:
void SetValue( int value );
int GetValue() const;
private:
int value_;
};
// Private class implementation
void
ClassA::ClassA_Impl::SetValue( int value ) {
value_ = value;
}
int
ClassA::ClassA_Impl::GetValue() const {
return value_;
}
// ClassA implementation
ClassA::ClassA() : m_pImpl( new ClassA_Impl() ) {}
ClassA::~ClassA() {}
void
ClassA::SetValue( int value ) {
m_pImpl->SetValue( value );
}
int
ClassA::GetValue() const {
return m_pImpl->GetValue();
}
ClassB: Pimpl class forward declaration and variable declaration on one line
ClassB.h:
#include <memory>
class ClassB {
public:
ClassB();
~ClassB();
void SetValue( int value );
int GetValue() const;
private:
std::unique_ptr<class ClassB_Impl> m_pImpl;
// ^^^^^^^^^^^^^^^^^^ class forward declaration
// combined with variable declaration on one line,
// in one shot.
//EDIT:
//Even if we use a raw pointer instead of a smart pointer,
//i.e. instead of declaring the smart pointer above, if we declare:
class ClassB_Impl *m_pImpl;
//the situation in the *.cpp files and my questions (below) are the same.
};
ClassB.cpp:
#include "ClassB.h"
class ClassB_Impl {
public:
void SetValue( int value );
int GetValue() const;
private:
int value_;
};
// Private class implementation
void
ClassB_Impl::SetValue( int value ) {
value_ = value;
}
int
ClassB_Impl::GetValue() const {
return value_;
}
// ClassB implementation
ClassB::ClassB() : m_pImpl( new ClassB_Impl() ) {}
ClassB::~ClassB() {}
void
ClassB::SetValue( int nValue ) {
m_pImpl->SetValue( nValue );
}
int
ClassB::GetValue() const {
return m_pImpl->GetValue();
}
Questions:
Why does combining the forward declaration and variable declaration on one line in ClassB.h require
ClassB_Impl
to be "unscoped" in the implementation of the private class in ClassB.cpp?i.e. in ClassA.cpp, private class method definitions begin with
void ClassA::ClassA_Impl::foo() {...
but in ClassB.cpp, private class method definitions begin with
void ClassB_Impl::foo() {...
What are the implications of each method? Which one is better?
(Follow-up question in response to Galik's answer)
When you combine forward declaration of a class and declaration of a variable of that class in one statement...
//one-liner class ClassB_Impl *m_pImpl;
...what is this called? Is there a name for this kind of combined statement? And why exactly doesn't
ClassB_Impl
become an inner class ofClassB
as a result of such a statement?Compare this to...
//two-liner class ClassA_Impl; ClassA_Impl *m_pImpl;
...in which case
ClassA_Impl
does become an inner class ofClassA
.Why does the one-liner put
ClassB_Impl
into the global namepace, while the two-liner putsClassA_Impl
intoClassA
's namespace? Why are they different?
Because in the first example you declare
ClassA_Impl
as an inner class ofClassA
.When you declare
ClassB_Impl
it in the template parameter that is not part ofClassB
.This is a matter of opinion. Personally I think inner classes are messy and harder to work with for little reward.
My preferred method uses a separate interface class which helps to reduce the number of times you have to redeclare the interface.
See: Is it possible to write an agile Pimpl in c++?