天天看點

C++實作反射(三)

新部落格連結

上一篇我們用一個 Object 類,讓所有需要反射的類都繼承這個對象,這樣雖然解決了問題,但是用起來不太友善。Object 類的存在主要為了解決儲存和傳回時的類型問題,如果取消這個類,我們怎麼對這些反射類做統一處理呢?答案當然是模闆。

  1. 實作一個模闆類管理類名和類構造函數的映射關系,并提供構造對象的接口,每個基類需要初始化一個這樣的管理對象。
  2. 提供一個對應的 static 模闆函數,用來儲存和傳回對應的管理對象。
  3. 使用模闆函數和 new 操作符作為每個類的構造函數。
  4. 實作一個簡單的 helper 模闆類提供作為注冊的簡單封裝,并封裝宏實作注冊。
  5. 封裝一個宏實作反射類的建立。
#ifndef __BASE_H__
#define __BASE_H__
#include <string>
#include <map>
#include <iostream>

// 使用模闆,每個基類單獨生成一個 ClassRegister
// 好處是需要反射的類不需要去繼承 Object 對象
// ClassRegister 用來管理類名->類構造函數的映射,對外提供根據類名構造對象對函數
template<typename ClassName>
class ClassRegister {
  public:
    typedef ClassName* (*Constructor)(void);
  private:
    typedef std::map<std::string, Constructor> ClassMap;
    ClassMap constructor_map_;
  public:
    // 添加新類的構造函數
    void AddConstructor(const std::string class_name, Constructor constructor) {
      typename ClassMap::iterator it = constructor_map_.find(class_name);
      if (it != constructor_map_.end()) {
        std::cout << "error!";
        return;
      }
      constructor_map_[class_name] = constructor;
    }
    // 根據類名構造對象
    ClassName* CreateObject(const std::string class_name) const {
      typename ClassMap::const_iterator it = constructor_map_.find(class_name);
      if (it == constructor_map_.end()) {
        return nullptr;
      }
      return (*(it->second))();
    }
};

// 用來儲存每個基類的 ClassRegister static 對象,用于全局調用
template <typename ClassName>
ClassRegister<ClassName>& GetRegister() {
  static ClassRegister<ClassName> class_register;
  return class_register;
}

// 每個類的構造函數,傳回對應的base指針
template <typename BaseClassName, typename SubClassName>
BaseClassName* NewObject() {
  return new SubClassName();
}

// 為每個類反射提供一個 helper,構造時就完成反射函數對注冊
template<typename BaseClassName>
class ClassRegisterHelper {
  public:
  ClassRegisterHelper(
      const std::string sub_class_name,
      typename ClassRegister<BaseClassName>::Constructor constructor) {
    GetRegister<BaseClassName>().AddConstructor(sub_class_name, constructor);
  }
  ~ClassRegisterHelper(){}
};

// 提供反射類的注冊宏,使用時僅提供基類類名和派生類類名
#define RegisterClass(base_class_name, sub_class_name) \
  static ClassRegisterHelper<base_class_name> \
      sub_class_name##_register_helper( \
          #sub_class_name, NewObject<base_class_name, sub_class_name>);

// 建立對象的宏
#define CreateObject(base_class_name, sub_class_name_as_string) \
  GetRegister<base_class_name>().CreateObject(sub_class_name_as_string)

#endif
           

下面是使用的示例:

#include <iostream>
#include <memory>
#include <cstring>
#include "base3.h"
using namespace std;

class base
{
  public:
    base() {}
    virtual void test() { std::cout << "I'm base!" << std::endl; }
    virtual ~base() {}
};

class A : public base
{
  public:
    A() { cout << " A constructor!" << endl; }
    virtual void test() { std::cout << "I'm A!" <<std::endl; }
    ~A() { cout << " A destructor!" <<endl; }
};

// 注冊反射類 A
RegisterClass(base, A);

class B : public base
{
  public :
    B() { cout << " B constructor!" << endl; }
    virtual void test() { std::cout << "I'm B!"; }
    ~B() { cout << " B destructor!" <<endl; }
};

// 注冊反射類 B
RegisterClass(base, B);

class base2
{
  public:
    base2() {}
    virtual void test() { std::cout << "I'm base2!" << std::endl; }
    virtual ~base2() {}
};

class C : public base2
{
    public :
    C() { cout << " C constructor!" << endl; }
    virtual void test() { std::cout << "I'm C!" << std::endl; }
    ~C(){ cout << " C destructor!" << endl; }
};

// 注冊反射類 C
RegisterClass(base2, C);


int main()
{
  // 建立的時候提供基類和反射類的字元串類名
  base* p1 = CreateObject(base, "A");
  p1->test();
  delete p1;
  p1 = CreateObject(base, "B");
  p1->test();
  delete p1;
  base2* p2 = CreateObject(base2, "C");
  p2->test();
  delete p2;
  return 0;
}