關(guān)于隱藏實(shí)現(xiàn)代碼
C++ 一直沒有學(xué)明白,對(duì)于一些問題,一直也沒有解決。
今天嘗試解決的問題,來源于微軟如何把它的庫實(shí)現(xiàn)隱藏起來。
之前的想法是,不管定義何種類和方法,總應(yīng)該在頭文件中出現(xiàn)聲明,
從而,一些private的方法和變量我們也應(yīng)該可以推斷出來。
但是,事實(shí)并不是這樣,很多時(shí)候,看到的只是public的。
而從理論上來說,應(yīng)該將實(shí)現(xiàn)與接口分離。像微軟提供的頭文件,
的確已經(jīng)定義好了固定的接口。而這樣,它們只需要再提供類庫,
我們就可以用了。
定義接口
首先,定義一個(gè)稱為 MyClass 的類,為了方便,我創(chuàng)建了一個(gè)目錄,
專門用于存放編譯我們自己類庫的代碼。
MyClass.h 的代碼非常簡(jiǎn)單:
#ifndef MyClass_H
#define MyClass_H
class MyClass {
public:
void run();
};
#endif
這個(gè)之后會(huì)暴露給用戶。但我們先不進(jìn)行實(shí)現(xiàn)。
實(shí)現(xiàn)隱藏代碼
下面,做的是真正的工作,即我們不需要給用戶看的。
定義 PrivateMyClass.h 和 PrivateMyClass.cpp 。
PrivateMyClass.h 內(nèi)容很簡(jiǎn)單:
#ifndef PrivateMyClass_H
#define PrivateMyClass_H
class PrivateMyClass {
public:
void canrun();
};
#endif
PrivateMyClass.cpp 也簡(jiǎn)單:
#include <iostream>
#include "PrivateMyClass.h"
void PrivateMyClass::canrun() {
std::cout << "Begin Can RUN?" << std::endl;
std::cout << "End Can RUN?" << std::endl;
}
封裝隱藏代碼
然后,我們?cè)?MyClass 的實(shí)現(xiàn)中,調(diào)用 PrivateMyClass 。
MyClass.cpp 內(nèi)容:
#include <iostream>
#include "MyClass.h"
#include "PrivateMyClass.h"
void MyClass::run() {
std::cout << "Begin RUN" << std::endl;
PrivateMyClass pmc;
pmc.canrun();
std::cout << "End RUN" << std::endl;
}
編譯生成動(dòng)態(tài)庫
有了這些,就可以編譯出動(dòng)態(tài)庫了,寫一個(gè) Makefile :
lib:MyClass.o PrivateMyClass.o
g++ -g -shared -o libresult.so MyClass.o PrivateMyClass.o
MyClass.o:MyClass.cpp MyClass.h
g++ -fPIC -Wall -g -c MyClass.cpp
PrivateMyClass.o:PrivateMyClass.cpp PrivateMyClass.h
g++ -fPIC -Wall -g -c PrivateMyClass.cpp
給出頭文件和動(dòng)態(tài)庫
這樣,我們就可把 MyClass.h 和 libresult.so 給用戶了。
我放到public的目錄下。
測(cè)試
為了確保正常運(yùn)行,寫代碼測(cè)試一下:
#include "MyClass.h"
int main() {
MyClass mc;
mc.run();
}
然后是Makefile:
all:exe
LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH ./result
test1:exe
LD_LIBRARY_PATH=../private/:$LD_LIBRARY_PATH ./result
test2:exe
LD_LIBRARY_PATH=../private-v2/:$LD_LIBRARY_PATH ./result
exe:TestClass.o
g++ -o result TestClass.o -L. -lresult
TestClass.o:TestClass.cpp
g++ -c TestClass.cpp
這個(gè)里面,包含了另外的一個(gè)測(cè)試:即庫更新后,
我是否可以不重新編譯用戶代碼。
結(jié)論是,可以不用重新編譯用戶代碼。