Table des matières

Interface (entête) du pimpl :

#pragma once
 
#include <memory>
 
class Fridge
{
 public:
  Fridge();
  Fridge(const Fridge& other) = delete;
  Fridge(Fridge&&);
  Fridge& operator=(const Fridge& other) = delete;
  Fridge& operator=(Fridge&&);
  ~Fridge();
  void coolDown();
 private:
  class FridgeImpl;
  std::unique_ptr<FridgeImpl> impl_;
};

Implémentation (source) :

#include "Fridge.h"
#include <iostream>
 
class Fridge::FridgeImpl
{
 public:
  void coolDown()
  {
    std::cout << "coucou\n";
  }
 private:
  int engine_;
};
 
Fridge::Fridge() : impl_(new FridgeImpl()) {}
Fridge::Fridge(Fridge&&) = default; 
Fridge& Fridge::operator=(Fridge&&) = default;
Fridge::~Fridge() = default;
void Fridge::coolDown() { impl_->coolDown(); }

GotW #100: Compilation Firewalls Archive du 27/11/2011 le 07/11/2019

C++ smart pointers fluentcpp

PImpl Archive le 30/10/2025

Détail

Pourquoi tout ça ?

Version de base

#include <memory>
 
class A {
   private:
    struct Aimpl;
    std::unique_ptr<Aimpl> impl;
};
 
int main() { auto p = std::make_unique<A>(A{}); }

Erreur : error: invalid application of 'sizeof' to incomplete type 'A::Aimpl'.

Version 2

Il faut empêcher de mettre inline le constructeur et le destructeur.

#include <memory>
 
class A {
   public:
    A();
    ~A();
 
   private:
    struct Aimpl;
    std::unique_ptr<Aimpl> impl;
};
 
int main() { auto p = std::make_unique<A>(A{}); }

Erreur : copy constructor of 'A' is implicitly deleted because field 'impl' has a deleted copy constructor.

Version 3

Ajout du constructeur et de l'opérateur move.

#include <memory>
 
class A {
   public:
    A();
    ~A();
    A(A&&) = default; 
    A& operator=(A&&) = default;
 
   private:
    struct Aimpl;
    std::unique_ptr<Aimpl> impl;
};
 
int main() {
    auto p = std::make_unique<A>(A{});
}

Erreur : invalid application of 'sizeof' to incomplete type 'A::Aimpl'.

Version 4

Même problème que Version 2. Il faut enlever le inline au constructeur et à l'opérateur move.

#include <memory>
 
class A {
   public:
    A();
    A(A&&); 
    A& operator=(A&&);
    ~A();
 
   private:
    struct Aimpl;
    std::unique_ptr<Aimpl> impl;
};
 
int main() {
    auto p = std::make_unique<A>(A{});
}

Il faut bien sûr implémenter A::A(), A::~A(), A::A(A&&), A& A::operator=(A&&) dans le .cpp.