c 實現類註冊機制的方法

2021-07-23 04:04:07 字數 2994 閱讀 5976

最近學習c++ 的反射機制的實現方式, 想要達到僅通過使用類名的字串就能方便地拿到該類例項的方法。要做到上述的目標,顯而易見的,我們需要使用某種機制記錄這種字串儲存的類名和類例項獲取方法(函式)的對映關係。 我們首先想到的就是用乙個std::map資料結構去訪問這種對映關係。 這個map 存貯在乙個工廠類中(這裡和工廠模式有些不同,但大體上是用來直接獲取例項的途徑。和工廠類類似,因此採用工廠類這個叫法,後面不再重述), 工廠類提供註冊對映關係和通過得到例項的方法。 再者如果每次新增乙個類, 都需要先在工廠類中完成註冊才能使用。那在應用**中加這些註冊的**,一來會使得耦合變強,二來每次手動註冊加重了應用層的工作量。 因此可以巧妙的設計乙個巨集來幫我們完成這塊。這樣再每次設計完乙個需要例項化的類後,可以立刻呼叫巨集註冊, 而在應用層面的**中手動註冊,讓**便於維護。

//工廠類標頭檔案class_factory.h

#ifndef _class_factory_h

#define _class_factory_h

#include #include #include "static_utils.h"

// 存放的是register中的 instance函式

typedef void * (*fun_ptr) ();

typedef std::mapcreate_obj_map;

class classfactory ;

#endif

//工廠類定義 class_factory.cpp

#include "class_factory.h"

void * classfactory::get_instance(const char* class_name)

std::cout << "found\n";

return _static::_static<0, create_obj_map>()[class_name]();

}void classfactory::register_class(const char* class_name, fun_ptr fp)

};#endif

// 要註冊的類,簡單舉列foo.h

#ifndef _foo_h

#define _foo_h

#include #include "register.h"

class foo

public:

int _id;

std::string _name;

};class foo1

public:

int _id;

std::string _name;

};register(foo);

register(foo1);

#endif

//main函式應用

#include #include "register.h"

#include "foo.h"

//register(foo);

//register(foo1);

int main()

以上就實現了利用類名字串獲取類例項的方法。 

當然在實現的過程中也遇到了一些問題, 心得總結如下 其中,一 是上面**我體會的一些核心思路和思想;二是在實現方式上遇到的問題及解決方法

1. 自動註冊,採用了反射機制

1.1 乙個工廠記錄了所有的類名和得到class obj的方法指標

1.1.1 工廠類中需要乙個註冊方法,記錄class_name和 得到class obj的函式

1.1.2 工廠類中需要乙個根據class_name 獲取class obj的函式,用來給應用方呼叫

1.1.3 以上兩條都是靜態方法

1.2 需要乙個輔助類,該類在建構函式中呼叫註冊

1.3 定義乙個巨集, 方便在寫**的時候用來完成註冊

1.3.1 巨集的本質是乙個類, 類裡有個靜態函式用來獲取註冊類的obj, 所以這個函式也就是1.1要的方法指標指向的東東

1.3.2 巨集定義的類中還需要乙個靜態成員變數, 該變數是乙個輔助類,這樣靜態變數初始化時呼叫輔助類的建構函式,就完成註冊過程

1.3.3 需要用傳給輔助類的是類名和這個類(1.3.1)的靜態函式名

1.3.4 靜態變數記得在類外初始化,這裡也需要定義在巨集裡

1.4使用的時候, eg 巨集register(類名)註冊後,可以直接使用工廠類的1.1.2獲取類的例項

2. 靜態變數初始化搗的鬼—工廠類中1.1如用靜態map記錄,會出core

2.1 由於程式中存在兩個靜態, 1.3.2中的靜態變數初始化的時候, 會呼叫2說的靜態map,此時map沒有被初始化,所以core

2.1.1 通俗的說就是 1.3.2 靜態變數依賴 2中的map ,因此有需要2 中變數先被初始化

2.1.2 不同環境下有些情況下可能不出core,原因是分散在不同檔案.cpp和.obj中的靜態變數初始化順序不定,所以不出core未必沒有風險

2.2 改進方法1. 將所有涉及靜態變數的涉及類放到乙個.cpp中, 將被依賴的初始化變數放在前就可以了,這樣2 的map就可以不要了

2.2 改進方法2. 上面方法不適合複雜場景因此做如下改造,解決的核心在於保證初始化順序,或者說確保用的時候,靜態變數一定存在

2.2.1 被依賴的靜態變數使用乙個自定義的類在此類的靜態函式中定義並返回需要型別的靜態變數

2.2.1.1 此方法的核心是static定義的靜態變數,僅初始化一次

2.2.1.2 函式的返回值是乙個靜態變數的引用, 因此可以作為左值使用

2.2.2 在所有用到改靜態變數的地方(2 map) 都呼叫2.2.1中定義的靜態函式

2.2.2.1 因為2.2.1.1的性質, 其實就實現了乙個單例模式,這樣保證在使用時,如果不存在就會去初始化使用

2.2.2.2 因為2.2.1.2的性質,保證該變數可作為左值進行賦值操作

Spark Master的註冊機制

master對其他元件註冊的處理 2.worker是在啟動後,主動向master註冊的,所以如果在生產環境下加入新的worker到已經正在執行的spark集群上,此時不需要重新啟動spark集群就可以使用新加入的worker以提公升處理能力。3.master在接受到worker註冊的請求後,首先會判...

加解密之 註冊機制實現

本文概要介紹基於加解密演算法的註冊機制設計思路 軟體版權的保護。軟體註冊碼機制需求場景。說明 1.用vgate公鑰加密對稱金鑰和演算法,是為了確保金鑰的保密性,進而確保了資料的保密性。2.用對稱金鑰加解密資料,是因為對稱加解密演算法加解密資料的速度比非對稱演算法加解密資料速度快。3.對原始報文做md...

C 序號產生器的實現

softreg類 using system using system.collections.generic using system.linq using system.text using system.management 需要引用system.management.dll namespace...