日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

RTTR(Run Time Type Reflection) C++反射原理实现剖解

發(fā)布時(shí)間:2024/1/1 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RTTR(Run Time Type Reflection) C++反射原理实现剖解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

C++反射是什么?

我個(gè)人理解的是運(yùn)行時(shí)獲取類的各種信息,類的成員變量,類的成員函數(shù),更具體的說(shuō)是運(yùn)行時(shí)一個(gè)類知道自己有幾個(gè)屬性,知道每個(gè)屬性的名字是什么, 可以通過名字運(yùn)行時(shí)訪問以及調(diào)用類的各種數(shù)據(jù),這就是C++反射。當(dāng)然非類的變量函數(shù)也是屬于C++反射的范圍,不過這里主要指代是Class(struct)相關(guān)的反射。看下面一段RTTR示例代碼

#include <iostream> #include<rttr/type> #include <rttr/registration> using namespace rttr;class MyStruct { public:MyStruct() {};void func(double a) {printf("a = %f\n", a);}; int data; RTTR_ENABLE() };class TestA : public MyStruct {public:TestA(){}RTTR_ENABLE(MyStruct) };class TestB : public TestA {public:TestB(){}RTTR_ENABLE(TestA) };//手動(dòng)注冊(cè)屬性方法和構(gòu)造函數(shù) RTTR_REGISTRATION {registration::class_<MyStruct>("MyStruct").constructor<>().property("adata", &MyStruct::data)(metadata("TOOL_TIP", "1121`Set the name of node."),metadata("TOOL_TIP1", "1121`Set the name of node.")).method("func", &MyStruct::func);registration::class_<TestA>("TestA").constructor<>();registration::class_<TestB>("TestB").constructor<>(); }int main() {//遍歷類的成員type t = type::get<MyStruct>();for (auto& prop : t.get_properties())std::cout << "name: " << prop.get_name() << std::endl;for (auto& meth : t.get_methods())std::cout << "name: " << meth.get_name() << std::endl;//創(chuàng)建類型的實(shí)例type t2 = type::get_by_name("MyStruct");variant var = t2.create(); // 方式1constructor ctor = t2.get_constructor(); // 方式2var = ctor.invoke();std::cout << "112= " << var.get_type().get_name() << std::endl; // 打印類型名稱//設(shè)置/獲取屬性MyStruct obj;property prop = type::get(obj).get_property("adata");prop.set_value(obj, 23);variant var_prop = prop.get_value(obj);std::cout << "metadata= " << prop.get_metadata("TOOL_TIP").to_string() << std::endl; // prints '23'std::cout << "1srfwe44= "<< prop.get_type().get_name() << std::endl; // prints '23'//調(diào)用方法MyStruct obj2;method meth = type::get(obj2).get_method("func");meth.invoke(obj2, 42.0);type a = type::get(obj2);variant var2 = a.create();meth.invoke(var2, 42.0);type b = type::get<TestB>();printf("b name is %s\n", b.get_name());array_range<type> baseClasses = b.get_base_classes();if (t.is_base_of(a)){printf("1111111111111111\n");}for (auto &baseclass : baseClasses){printf("base class name is %s\n", baseclass.get_name());}auto ss = &MyStruct::data;std::cout << "fsdd11111= " << typeid(a).name() << std::endl; // prints '23'MyStruct aassdd;type cc = type::get(aassdd);std::cout << "aassdd= " << cc.get_name() << std::endl; // prints '23'system("pause");return 0; }

輸出:

?

RTTR的核心數(shù)據(jù)結(jié)構(gòu)

type_register_private---------type

type-----property,method,metadata

?

下面的各種分析都是以上面代碼例子來(lái)分析

C++反射-類型(type)的實(shí)現(xiàn)

RTTR數(shù)據(jù)類型類為 type,記錄了“int,float,class等類型的類型數(shù)據(jù)”,比如 class MyStruct?的類型數(shù)據(jù), 記錄了類 MyStruct?的名字為“MyStruct?”

?

類型數(shù)據(jù)(type)的類型結(jié)構(gòu)

類型數(shù)據(jù)(type)的注冊(cè)流程

上面是大致的簡(jiǎn)略版調(diào)用函數(shù)棧, 簡(jiǎn)約歸為:在運(yùn)行時(shí),獲取一個(gè)類的type_data, 然后構(gòu)造出type, 最后把type存儲(chǔ)到type_private_data單例管理里。可以看到m_src_name_to_idm_custom_name_to_id是兩個(gè)map, 以類型名為key,以type為value.

m_src_name_to_id存放的key是類型的原名,m_custom_name_to_id存放的key是后定制的名

這里有個(gè)非常重要的執(zhí)行過程,構(gòu)造type_data的過程,因?yàn)閠ype_data存著type最重要的數(shù)據(jù), 也就是類型的原生名

? ?

RTTR反射框架獲取類型原名是統(tǒng)統(tǒng)編輯器內(nèi)置宏來(lái)獲取的,比如MSVC的__FUNCSIG__,GUNC的__PRETTY_FUNCTION__,CLANG或者APPLECLANG的__PRETTY_FUNCTION__,下面主要是實(shí)現(xiàn)代碼

類型數(shù)據(jù)(type)的相關(guān)接口的實(shí)現(xiàn)

type::get(T&& object)

主要是模板推導(dǎo), 從object推導(dǎo)其類型,就可以從type_private_data從遍歷尋找相應(yīng)的type數(shù)據(jù)

type::get_by_name(string_view name)

直接從type_private_data中遍歷m_custom_name_to_id哈希表來(lái)查找type

?

C++反射-屬性(property)的實(shí)現(xiàn)

類內(nèi)的各種變量為屬性, 類屬性指針的表現(xiàn)比較特別。看看下面的例子,可以看出每個(gè)類內(nèi)的變量類型是以類為前綴的,比如?MyStruct?的?int?變量成員類型就是int MyStruct::*, 我們可以通過類的實(shí)例對(duì)象和類變量指針進(jìn)行訪問。

類屬性數(shù)據(jù)(property)的數(shù)據(jù)結(jié)構(gòu)

類屬性數(shù)據(jù)(property)的注冊(cè)流程

上面是大致的簡(jiǎn)略版調(diào)用函數(shù)棧,簡(jiǎn)略歸納為 聲明獲取property的虛函數(shù)的接口基類property_wrapper_base。通過property_wapper模板類繼承接口類,并利用模板推導(dǎo)一個(gè)屬性為 “m_acc: A (C::*)”。而接口基類指針存在property里,property訪問真正的類屬性指針就忽視了類型,直接通過property_wrapper_base接口就能訪問。這樣既可以讓class_data保存一個(gè)整齊無(wú)模板的property數(shù)組,又讓property可以間接包含了類屬性指針。

類型數(shù)據(jù)(property)的相關(guān)接口的實(shí)現(xiàn)

property get_property(string_view name)

實(shí)現(xiàn)上就是從type_data的class_data中property數(shù)組中遍歷尋找

?

C++反射-方法(method)的實(shí)現(xiàn)

類內(nèi)的各種執(zhí)行函數(shù)為方法, 類方法指針和上面所說(shuō)的類屬性指針類似。看看下面的例子,可以看出每個(gè)類內(nèi)的函數(shù)指針是以類為前綴的,比如?MyStruct?PrintA?函數(shù)類型就是 void (MyStruct::*)(int), 我們可以通過類的實(shí)例對(duì)象和類變量指針進(jìn)行訪問。

類函數(shù)數(shù)據(jù)(method)的數(shù)據(jù)結(jié)構(gòu)

RTTR框架中 method的數(shù)據(jù)結(jié)構(gòu)和property的數(shù)據(jù)結(jié)構(gòu)非常類似

類方法數(shù)據(jù)(method)的注冊(cè)流程

上面是大致的簡(jiǎn)略版調(diào)用函數(shù)棧, 過程和property的非常類似。簡(jiǎn)略歸納為 聲明獲取method各種基礎(chǔ)屬性的虛函數(shù)的接口基類method_wrapper_base。通過method_wapper模板類繼承接口類,并利用模板推導(dǎo)一個(gè)函數(shù)類型為 “F”。而接口基類指針存在method里,method訪問真正的函數(shù)指針變量就忽視了類型,直接通過property_wrapper_base接口就能訪問。這樣既可以讓class_data保存一個(gè)整齊無(wú)模板的method數(shù)組,又讓method可以間接包含了類函數(shù)指針。

?

類型數(shù)據(jù)(method)的相關(guān)接口的實(shí)現(xiàn)

?method get_method(string_view name)

實(shí)現(xiàn)和get_property的類似,都是從class_datam_methods數(shù)組中遍歷查找。

?

類型(type)的子類型(derived_class), 父類型(base_class)注冊(cè)

個(gè)人舉得 這部分是RTTR框架實(shí)現(xiàn)得最精彩的部分,先看案例代碼。下面?RTTR_ENABLE 將 TestA父類注冊(cè)為MyStrcut和A, 換句話說(shuō),同時(shí)也將MyStrcut 和 A的子類注冊(cè)為TestA

derived_class和base_class的數(shù)據(jù)結(jié)構(gòu)

?

derived_class和base_class的注冊(cè)流程

base_class 和?derived_class的發(fā)生在創(chuàng)建一個(gè)type的type_data的時(shí)候

? ? ? ? ??

?

這里 DerivedClass為目前創(chuàng)建類型type數(shù)據(jù)的類, 也就是示例代碼的“TestA”.? ??"has_base_class_list"假設(shè)一個(gè)類聲明了base_class_list類型,就進(jìn)行類型列表的遞歸編譯(其中某些類型可能也聲明了RTTR_ENABLE,存在類型列表),在靜態(tài)函數(shù)中對(duì)每一個(gè)繼承類型進(jìn)行遞歸查找他們相應(yīng)的type,然后加入vector<type>中,最終為type的type_data數(shù)據(jù)生成了base_classes(std::vector<type>)

這里最大的亮點(diǎn)在于:編譯期進(jìn)行遞歸,生成查找注冊(cè)的類型列表中所有類型的代碼。

當(dāng)然此時(shí)type_data的class_data還沒具備m_base_types和m_derived_types,子類型和父類型的實(shí)現(xiàn)是在注冊(cè)type到 type_private_data單例管理類的時(shí)候,具體參考上面 “type生成的函數(shù)棧”。

value

?

metadata的實(shí)現(xiàn)

無(wú)論是類型的元數(shù)據(jù),屬性的元數(shù)據(jù),方法的元數(shù)據(jù),本質(zhì)是就是key-value的map。實(shí)現(xiàn)方式很多,在RTTR里 property和mehod的元數(shù)據(jù)實(shí)現(xiàn)都是在相應(yīng)的wrapper類繼承metahandle, 沒啥特殊的,所以就不詳細(xì)分析實(shí)現(xiàn)原理。

?

參考資料

(1)__FUNCSIG__、__FUNCDNAME__、__FUNCTION__、__func__、__PRETTY_FUNCTION__

(2)C++ 類成員函數(shù)的函數(shù)指針

(3)C++獲取類中成員函數(shù)的函數(shù)指針

?

總結(jié)

以上是生活随笔為你收集整理的RTTR(Run Time Type Reflection) C++反射原理实现剖解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。