pimpl完全的資訊隱藏

  1. pimpl完全的資訊隱藏
    1. 極致的資訊隱藏手法
    2. 使用Smart Pointer
    3. pImpl的優點
    4. pImpl的缺點
      1. 參考資料: 

pimpl完全的資訊隱藏

原文連結: https://darkblack01.blogspot.com/2015/03/pimpl.html
移植時的最後更新日期: 2015-12-23T14:16:57.729+08:00

pimpl(pointer to implementation), 指向實作的指標。 這是《API Design for C++》Ch3.1的心得整理。
在此是要介紹,在C中,如何實現「資訊隱藏狂熱」,class裡完全的將public以外的東西隱藏掉,在API設計中,這是很重要的,避免錯誤的使用,也讓設計更簡單好記。

在此,作者也有提到Effective C
#34也有提及這個技巧。
無獨有偶的,Code Complete 2/e中也有提到。不過在《API Design for C++》中有強調,這是C獨有的技巧,所以不算是通用的Design Pattern,不過,算是很厲害的Design Pattern for C

(在此,不使用書中的範例程式)
這個例子,是隱藏.cpp裡一切細節的範例程式的延伸版。
類別要描述的是「不會透露自己的年紀的人」。
透過pimpl技巧,強調「不會透露自己的年紀的人,更不會跟別人透露不想提及的意圖」。

//Person.h
#include <string>
#include “date.h”
#include "address.h"

class Person
{
std::string theName;
Date theBirthDate;
Address theAddress;
int GetYears(int currYear);
public:
Person();
~Person();
Person(const std::string& name,
const Date& birthday,

std::string name() const;
std::string birthDate() const;
std::string address() const;
//…
};

極致的資訊隱藏手法

我們希望它可以只露出必要的部份,所以將它改寫成這樣
//Person.h
#include <string>
#include “date.h”
#include "address.h"

class Person
{
class PersonImpl; //如果使用上造成太多存取的限制,可以考慮將這一行改成public
PersonImpl* pImpl; //宣告一個實作類別的指標(或參考也行,就是不可以是實體)
public:
Person();
~Person();
Person(const std::string& name,
const Date& birthday,
const Address& addr);

std::string name() const;
std::string birthDate() const;
std::string address() const;
//…
};
//Person.cpp
#include "Person.h"

class Person::PersonImpl
{
public:
std::string theName;
Date theBirthDate;
Address theAddress;

int GetYears(int currYear)
{
return currYear - BirthDate.Year();
}
};

Person::Person(const std::string& name,
const Date& birthday,
const Address& addr):
pImpl(new PersonImpl())
{
pImpl->theName = name;
pImpl->theBirthDate = birthday;
pImpl->theAddress = addr;
};

Person::~Person()
{
delete pImpl;
pImpl = 0;
}
除此之外,對於類別的複製建構式與賦值運算子的override都是必須要注意的實作細節唷。

使用Smart Pointer

書裡還建議使用smart pointer避免使用這種方式時,pimpl實作不見了的情況。
//Person.h
#include <personimpl>
#include “date.h”
#include "address.h"

class Person
{
class PersonImpl; //如果使用上造成太多存取的限制,可以考慮將這一行改成public
std::unique_ptr pImpl; //使用適合的Smart Pointer
public:
Person();
~Person();
explicit Person(const std::string& name,
const Date& birthday,
const Address& addr);

std::string name() const;
std::string birthDate() const;
std::string address() const;
//…
};
  • shared_ptr 指向相同的物件,誤刪不消失。 
  • scoped_ptr 保證唯一,無法複製。

pImpl的優點

  • Information Hidding
  • 降低耦合
  • 加快編譯

pImpl的缺點

  • 增加一點點的物件大小
  • 降低程式碼可讀性
  • 提高維護程本(除錯時要追程式碼就困難許多了)
  • 類別中的const函數,無法保證private的成員變數唯讀(只保證pImpl的指標不改變)

而這篇就是紀錄書中,如何改寫的注意事項。
詳細的細節,還是去看書吧!^^這本書很棒唷!

參考資料: 

[1] 3.1 Pimpl慣用語 - C++ API 設計