Saya melihat banyak kode sumber yang menggunakan idiom PImpl di C ++. Saya berasumsi bahwa tujuannya adalah untuk menyembunyikan data / tipe / implementasi pribadi, sehingga dapat menghapus ketergantungan, dan kemudian mengurangi waktu kompilasi dan header menyertakan masalah.
Tetapi antarmuka / kelas abstrak murni di C ++ juga memiliki kemampuan ini, mereka juga dapat digunakan untuk menyembunyikan data / tipe / implementasi. Dan untuk membiarkan pemanggil melihat antarmuka saat membuat objek, kita dapat mendeklarasikan metode pabrik di header antarmuka.
Perbandingannya adalah:
Biaya :
Cara antarmuka biaya lebih rendah, karena Anda bahkan tidak perlu mengulangi implementasi fungsi public wrapper
void Bar::doWork() { return m_impl->doWork(); }
, Anda hanya perlu mendefinisikan tanda tangan di antarmuka.Dipahami dengan baik :
Teknologi antarmuka lebih baik dipahami oleh setiap pengembang C ++.
Kinerja :
Cara kinerja antarmuka tidak lebih buruk daripada idiom PImpl, keduanya merupakan akses memori tambahan. Saya menganggap kinerjanya sama.
Berikut ini adalah kodesemu untuk mengilustrasikan pertanyaan saya:
// Forward declaration can help you avoid include BarImpl header, and those included in BarImpl header.
class BarImpl;
class Bar
{
public:
// public functions
void doWork();
private:
// You don't need to compile Bar.cpp after changing the implementation in BarImpl.cpp
BarImpl* m_impl;
};
Tujuan yang sama dapat diimplementasikan menggunakan antarmuka:
// Bar.h
class IBar
{
public:
virtual ~IBar(){}
// public functions
virtual void doWork() = 0;
};
// to only expose the interface instead of class name to caller
IBar* createObject();
Jadi apa gunanya PImpl?
sumber
Impl
kelas tidak akan merusakABI
, tetapi menambahkan fungsi publik di antarmuka akan merusakABI
.unordered_set
), Tanpa PImpl, saya harus#include <unordered_set>
masukMyClass.h
. Dengan PImpl, saya hanya perlu memasukkannya ke dalam.cpp
file, bukan.h
file, dan karena itu segala sesuatu yang memasukkannya ...Saya hanya ingin membahas poin kinerja Anda. Jika Anda menggunakan antarmuka, Anda harus telah membuat fungsi virtual yang TIDAK AKAN diuraikan oleh pengoptimal kompiler. Fungsi PIMPL dapat (dan mungkin akan, karena mereka sangat pendek) digarisbawahi (mungkin lebih dari sekali jika fungsi IMPL juga kecil). Panggilan fungsi virtual tidak dapat dioptimalkan kecuali Anda menggunakan optimasi analisis program lengkap yang membutuhkan waktu sangat lama.
Jika kelas PIMPL Anda tidak digunakan dengan cara yang kritis terhadap kinerja, maka poin ini tidak terlalu menjadi masalah, tetapi asumsi Anda bahwa kinerjanya sama hanya berlaku di beberapa situasi, tidak semua.
sumber
Halaman ini menjawab pertanyaan Anda. Banyak orang setuju dengan pernyataan Anda. Menggunakan Pimpl memiliki keunggulan berikut di atas bidang / anggota pribadi.
Ungkapan Pimpl adalah optimasi waktu kompilasi, teknik pemecahan ketergantungan. Ini memotong file header besar. Ini mengurangi header Anda menjadi hanya antarmuka publik. Panjang header penting dalam C ++ ketika Anda berpikir tentang cara kerjanya. #include secara efektif menggabungkan file header ke file sumber - jadi ingatlah setelah unit C ++ yang pra-diproses bisa sangat besar. Menggunakan Pimpl dapat meningkatkan waktu kompilasi.
Ada teknik pemecahan ketergantungan lain yang lebih baik - yang melibatkan peningkatan desain Anda. Apa yang diwakili metode pribadi? Apa tanggung jawab tunggal? Haruskah mereka menjadi kelas lain?
sumber