介绍:
Pimpl idiom意为“pointer to imprementation”,即指向实现的指针,这样方法是把某个类分割成两个classes,一个只提供接口,另一个负责实现该接口,这样便实现了接口与实现分离,这个分离方式的关键在于以“声明的依存性”替换“定义的依存性”,从而达到编译依存性最小化的目的。可以说Pimpl是C++的一种惯用模式。
实现:
PIMPL基于这样一个事实:在C++类中,允许定义一个成员指针,指向一个已声明过的类型。在头文件中只是存放该类型的声明,而具体的定义是存放在CPP文件中,这样就可以隐藏类型的具体实现。
例子:
Book.h文件:
#ifndef BOOK_H_
#define BOOK_H_
#include <iostream>
#include <memory>
// 这是一个声明文件,作为接口类,这样不管BookImpl类的实现怎么修改都不影响接口的使用
class Book{
public:
Book(std::string name, std::string author);
~Book();
Book(const Book& b);
Book& operator=(const Book& b);
void print();
private:
class BookImpl; // Book实现类的前置声明,Book的内嵌类
std::shared_ptr<BookImpl> mp_impl;
};
#endif
BookPimpl文件:
#ifndef BOOK_PIMPL_H__
#define BOOK_PIMPL_H__
#include "Book.h"
// 这是一个定义类,具体实现在cpp中,不需要提供给客户,达到与声明类分离
// BookImpl在Book类了进行了前置声明,相对于是Book类的内嵌类
class Book::BookImpl {
public:
BookImpl(std::string name, std::string author);
~BookImpl();
void print();
private:
std::string m_title;
std::string m_author;
};
#endif
Book.cpp文件:
#include "Book.h" // 需要实现Book.h类
#include "BookPimpl.h" // 需要调用BookPimpl的成员函数
#include <string>
Book::Book(std::string name, std::string author):mp_impl(new BookImpl(name, author)) {
}
Book::~Book() {}
Book::Book(const Book& b) {}
Book& Book::operator=(const Book& b) {
return *this;
}
void Book::print() {
mp_impl->print();
}
Book::BookImpl::BookImpl(std::string name, std::string author) {
m_title = name;
m_author = author;
}
Book::BookImpl::~BookImpl() {}
void Book::BookImpl::print() {
std::cout << "book title " << m_title << " book author " << m_author << std::endl;
}
Main.cpp文件
#include "Book.h"
int main(int argc, char* argv[]) {
Book book("C++", "sampson");
book.print();
return 0;
}
这样,Book作为声明类,BookPimpl作为定义类,具体的实现放在BookPimpl类中通过cpp文件实现,客户只需要拿到Book.h文件即可,不用关心具体的实现。当具体实现发生修改时也不需要重新编译客户代码。