C++ ile PIMPL IDIOM Nedir?

C++ ile PIMPL IDIOM Nedir?

Herkese merhabalar, bu yazımızda sizlerle C++ programlama dilinde bizlere dciddi derecede kolaylık sağlayan PIMPL Idiom hakkında konuşacağız ve örnekler yapacağız.

Hadi Başlayalım

C++ programlarında header dosyalarında sınıfların değişkenleri ve fonksiyonları tanımlanır. Bu yüzden header dosyalarında herhangi bir değişiklik yapıldığında, ilgili header dosyasını include eden bütün sınıflar yeniden derlenir. Büyük projelerde bu durum fazlaca vakit kaybına sebep olmaktadır. PIMPL Idiom tekniği sayesinde sınıfların kendi implementasyonlarını böleriz ve sadece ilgili sınıfın derlenmesini sağlarız. Bu sayede vakit kaybı önlenmiş olmaktadır.

Ayrıca PIMPL Idiom ile sınıf içerisindeki private tanımlamaları diğer sınıflardan tam olarak izole edebilmekteyiz. Bu sayede ilgili header dosyası değiştiğinde ilgili bütün sınıfın yeniden derlenmesi yerine sadece değişiklik yapılan implementasyon sınıfı yeniden derlenecektir. İlgili implementasyon sınıfına ise tanımlanan bir pointer aracılığı ile erişebileceğiz.

Ayrıca tanımlanan bir constructor ve destructor metodları yardımı ile de PIMPL sınıfının pointer tanımlamasını akıllı pointer haline getiririz ve derleyici copy constructor mantığı ile onada bir constructor ve destructor tanımlar. Ek olarak yazmaya gerek kalmaz.

PIMPL Idiom Pointer to Implementation ifadesinin kısaltılmış halidir. Pimpl Idiom ile aynı sınıfa include eden sınıfların private Implementasyonları ayrılır ve kendi implementasyon sınıflarında tanımlanırlar. Beraberinde bir pointer aracılığı ile erişim sağlanmasına olanak tanınır.

PIMPL Idiom nasıl uygulanır.
  • İlk olarak ilgili tanımlamalar için ayrı bir sınıf veya struct oluşturulur.
  • Oluşturulan bütün private tanımlamalar, oluşturulan bu sınıfa tanınır.
  • Sonrasında bir Implementasyon sınıfı oluşturulur. Genellikle bu sınıflar Impl son eki ile oluşturulur. Örn : MyClassImpl.
  • İlgili sınıfta ise oluşturulan bu Implementasyonj sınıfı için bir pointer oluşturulur ve implementasyona bu pointer aracılığı ile erişilmesi sağlanır.
  • Son olarak implementasyon sınıfına bir constructor ve destructor tanımlanır. Bu sayede Implementasyon sınıfını işaret eden pointer akıllı pointer'a dönüştürülür.

Şimdi örneğimize geçelim.

theclass.h

#include <iostream>
#include <QString>

//unique_ptr için gerekli olan kütüphane
#include <memory>

using namespace std;

//Sınıf prototip tanımlaması
class TheClassImpl;

class TheClass
{
public:
    //Default constructor ve Destructor
    explicit TheClass();
    ~TheClass();

    //Copy Constructor
    TheClass(const TheClass& rhs);
    TheClass& operator=(const TheClass& rhs);

    //Getter ve Setter metodlar
    void set(QString name, QString surname);
    QString get() const;

private:
    const TheClassImpl* Pimpl() const { return pimpl.get(); }
    TheClassImpl* Pimpl() { return pimpl.get(); }

    std::unique_ptr<TheClassImpl> pimpl;
};
  • İlk olarak Header dosyamızı oluşturalım. İlk olarak sınıfımızın tanımlaması yapılır. Burada sınıfımızın yapıcı ve yıkıcı metodları ile birlikte Copy Constructor metodlarınıda oluşturmamız gerekmektedir. Ardından getter ve setter metodlarımızıda oluştururuz.
  • Şimdi önemli kısma geçelim. Bir implementasyon sınıfı oluşturalım ve bütün private metod ve değişkenleri oluşturulan bu implementasyon sınıfına taşırız.
  • Ardından Sınıfımızın private kısmında, tanımlanan bu implementasyon sınıfına bir pointer oluştururuz.

Bu tanımlamada unique_ptr kullanmamızın amacı programın hayat döngüsü boyunca bellekten silinmeden hep aynı adresinde tutulmasını sağlamaktır.

Şimdi sınıfımızın tanımlamalarını ve implementasyon sınıfımızın tanımlamalarını yapalım.

theclass.cpp

#include "theclass.h"

class TheClassImpl
{
private:
    QString name;
    QString surname;

public:
    ~TheClassImpl() = default;

    void setNameSurname(QString _name, QString _surname)
    {
        name = _name;
        surname = _surname;
    }

    QString getNameSurname() const
    {
        return name + " "+ surname;
    }
};

TheClass::TheClass() : pimpl(new TheClassImpl()){ }
TheClass::~TheClass() = default;

TheClass::TheClass(const TheClass& rhs) : pimpl(new TheClassImpl(*rhs.pimpl))
{}

TheClass& TheClass::operator=(const TheClass& rhs) {
    if (this != &rhs)
        pimpl.reset(new TheClassImpl(*rhs.pimpl));

    return *this;
}

void TheClass::set(QString name, QString surname)
{
    Pimpl()->setNameSurname(name, surname);
}

QString TheClass::get() const
{
    return Pimpl()->getNameSurname();
}

Burada implementasyon sınıfının tanımlaması yapıldı ve kullanacak oluğumuz sınıftan ilgili metodlar yazılarak getter ve setter metodları çağrıldı. Bu metodlar üzerinden PIMPL sınıfına erişilerek gerekli işlemler yapıldı.

Son olarak main fonksiyonumuzdan sınıfımızı çağırarak kullanımı görmüş olalım.

main.cpp

#include <QCoreApplication>
#include <iostream>
#include "theclass.h"

using namespace std;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    system("title C++ PIMPL IDIOM Example - Thecodeprogram");
    cout << "C++ ile PIMPL IDIOM örneğine hoşgeldiniz..." << endl << endl;

    TheClass *mc = new TheClass();
    mc->set("Burak Hamdi", "TUFAN");
    QString v = mc->get();

    cout << v.toUtf8().constData() << endl << endl;

    return a.exec();
}

C++ Pimpl Idiom Örneği Çıktısı

C++ Pimpl Idiom Example Output
PIMPL Tekniğinin avantajları:
  • Değişiklik yapılan bütün sınıf ve ona bağlı bütün Implementasyon dosyaları yeniden derlenmeyecek olupi, sadece değişiklik yapılan implementasyon sınıfı derlenecektir. Bu sayede derleme süresi ciddi oranda azalacaktır.
  • Private veriler tam olarak gizlenebilmektedir. PIMPL ile geliştirlen kütüphaneler dışarıya açıldığında sadece ilgili public metodlar dışarıya verilebilecek ve diğer private tanımlar gizlenmiş olacaktır.
  • Tanımla sınıfıın implementasyonları bölüneceği için birbirinden bağımsız olacaktır. Bu sayede birinde yapılan bir hata diğer sınıfı işleyişini bozmayacaktır.
PIMPL Tekniğinin Dezavantajları
  • Uygulama içerisindeki sınıfların sayısı artacağından dolayı ileriye dönük geliştirmelere biraz daha zaman alabilecektir.
  • Private olarak tanımlanan bir sınıf tanımlamaları harici sınıflar tarafından kalıtım alınılsa bile erişilemezler. Fakat PIMPL sınıfı, ilgili sınıfın bir üyesi olduğu için kalıtım almamış olsa bile private tanımlamalara erişebilir.
  • Herbir PIMPL sınıfı için ayrı ayrı bellek kullanımı gerekeceğinden dolayı, uygulamadaki bellek kullanımı artacaktır. Gömülü sistem yazılımlarında bu durum göz önüne alınmalıdır.

Bu yazımızda buraya kadar.

Burak Hamdi TUFAN


Tags


Share this Post

Send with Whatsapp

Post a Comment

Success! Your comment sent to post. It will be showed after confirmation.
Error! There was an error sending your comment.

Comments

  • There is no comment. Be the owner of first comment...