I try to understand the PIMPL idiom.
I have several files, let's say "Implementation.cpp/Implementation.h" implement the PIMPL idiom: it contains a public interface and a private implementation.
"Client.cpp/Client.h" use the public interface.
Another file "main.cpp" just uses the client class.
I wrote a very simple makefile.
At first, everything compiles:
g++ -std=c++11 -c main.cpp
g++ -std=c++11 -c Implementation.cpp
g++ -std=c++11 -c Client.cpp
g++ -o main main.o Implementation.o Client.o -std=c++11
I wanted to prouve that if I modify something in the PIMPL implementation, the client will not recompile, and that if I do no use the PIMPL idiom (If I do a modification in the public interface) the client will recompile.
Compiler output when private implementation is modified:
g++ -std=c++11 -c Implementation.cpp
g++ -o main main.o Implementation.o Client.o -std=c++11Compiler output when public interface (new method, new member with initialization, etc) is modified:
g++ -std=c++11 -c Implementation.cpp
g++ -o main main.o Implementation.o Client.o -std=c++11
Actually, it is the same.
My expectation was, if I modify something in the public interface it should recompile both "Implementation" and "Client":
g++ -std=c++11 -c Implementation.cpp
g++ -std=c++11 -c Client.cpp
g++ -o main main.o Implementation.o Client.o -std=c++11
What does the compiler really do, and how can I check that the compiler only compile the necessary when using PIMPL idiom?
EDIT (code added):
Implementation.cpp:
#include "Implementation.h"
class PublicInterface::PrivateImplementation
{
public:
PrivateImplementation(std::string name) : name(name), id(0){};
virtual ~PrivateImplementation(void){};
std::string name;
int id;
};
PublicInterface::PublicInterface(std::string name) : pImplPrivate(new PrivateImplementation(name)){}
PublicInterface::~PublicInterface() = default;
int PublicInterface::GetID(void) const { return this->pImplPrivate->id;}
void PublicInterface::SetID(const int id) { this->pImplPrivate->id = id;}
Implementation.h:
#include <memory>
#include <string>
class PublicInterface
{
public:
PublicInterface(std::string name);
virtual ~PublicInterface(void);
int GetID(void) const;
void SetID(const int id);
private:
class PrivateImplementation;
std::unique_ptr<PrivateImplementation> pImplPrivate;
};
client.cpp:
#include <iostream>
#include "Client.h"
#include "Implementation.h"
Client::Client(void){}
Client::~Client(void){}
void Client::Caller(void)
{
PublicInterface interface(std::string("Interface"));
std::cout << "Interface ID " << interface.GetID() << std::endl;
interface.SetID(5);
std::cout << "Interface ID " << interface.GetID() << std::endl;
}
client.h:
class Client
{
Client(void);
virtual ~Client(void);
public:
static void Caller(void);
static void Another(void);
};
main.cpp:
#include "Client.h"
int main(int argc, char** argv)
{
Client::Caller();
return 0;
}
Makefile:
CPPFLAGS=-std=c++11
main : main.o Implementation.o Client.o
g++ -o main main.o Implementation.o Client.o $(CPPFLAGS)
main.o : main.cpp
g++ $(CPPFLAGS) -c main.cpp
Implementation.o : Implementation.cpp
g++ $(CPPFLAGS) -c Implementation.cpp
Client.o : Client.cpp
g++ $(CPPFLAGS) -c Client.cpp
clean :
rm main main.o Implementation.o Client.o