C++使用宏函数实现单例模板详解

下面就为你详细讲解“C++使用宏函数实现单例模板详解”的完整攻略。

1. 单例模式简介

单例模式是一种创建型设计模式,它确保某个类只有一个实例,并提供一个全局访问点,使得该实例能够被访问。单例模式在很多场景下都有非常重要的作用,例如线程池、配置文件读取等。

2. 使用宏函数实现单例模板

C++中使用宏函数可以方便地实现单例模板。具体实现步骤如下:

  1. 定义一个模板类,并将构造函数、拷贝构造函数、赋值运算符等函数都定义为private,以避免在类外部实例化该类。
template<typename T>
class Singleton{
private:
    Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
public:
    static T& instance() {
        static T t {};
        return t;
    }
};
  1. 调用宏函数定义单例模板的基本代码块,可将其命名为DECLARE_SINGLETON
#define DECLARE_SINGLETON(class_name) \
    friend class Singleton<class_name>; \
    class_name() = default; \
    virtual ~class_name() = default;
  1. 在定义类中使用DECLARE_SINGLETONpublic:,可实现添加到单例类模板的基本成员函数。
class Test {
public:
    DECLARE_SINGLETON(Test)
    void func() {
        std::cout << "test func" << std::endl;
    }
};
  1. 在需要使用单例模板的地方,调用instance()函数即可获取该单例的唯一实例。
Test& t = Singleton<Test>::instance();
t.func(); // test func

至此,单例模板的基本代码框架已经搭建完成。对于一些较为复杂的应用场景,还需要在单例模板中添加一些额外的成员函数和变量才能满足需求。

3. 示例说明

下面是两个示例,分别演示了如何使用宏函数实现单例模板。

示例1

下面是一个用于保存游戏得分的单例模板类。

template<ScoreType TYPE>
class ScoreManager final {
public:
    DECLARE_SINGLETON(ScoreManager)
    int get_score() {
        return score_;
    }
    void add_score(int score) {
        score_ += score;
    }
private:
    int score_ {};
};

该模板类应具体化为两个不同的类型:ScoreType::EasyScoreType::Hard,分别表示不同难度级别的游戏得分管理器。可以使用宏定义SCORE_MANAGER自动化生成两个具体类并定义一个简单的全局函数。

#define SCORE_MANAGER(type) \
    class ScoreManager##type : public ScoreManager<ScoreType::type> {\
    public: ScoreManager##type() {} virtual ~ScoreManager##type() = default; \
    }; \
    static inline auto& Get##type############Singleton() { \
        return Singleton<ScoreManager##type>::instance(); \
    }
SCORE_MANAGER(Easy)
SCORE_MANAGER(Hard)

上述代码利用了##标记来进行宏函数替换,以自动定义具体化的类名和全局函数名。

例如,SCORE_MANAGER(Easy)宏展开后,生成的具体类名为ScoreManagerEasy,全局函数名为GetEasySingleton(),其调用方法为:

auto& score_manager_easy = GetEasySingleton();
score_manager_easy.add_score(100);
std::cout << score_manager_easy.get_score() << std::endl; // 100

同理,SCORE_MANAGER(Hard)生成的具体类名为ScoreManagerHard,全局函数名为GetHardSingleton()。由于ScoreManager类的构造函数为private,因此只能通过使用GetEasySingleton()GetHardSingleton()方法来获取其唯一实例。

示例2

下面是一个用于保存各种配置文件的单例模板类。

template<typename T>
class ConfigManager final {
public:
    DECLARE_SINGLETON(ConfigManager)
    bool load(const std::string& file_path) {
        try {
            std::ifstream file_stream(file_path);
            if (file_stream.fail()) throw;
            T config;
            nlohmann::json json_config;
            file_stream >> json_config;
            json_config.get_to(config);
            configs_.push_back(std::move(config));
            return true;
        } catch (...) {
            return false;
        }
    }
    const T& get(int index = 0) const {
        return configs_[index];
    }
private:
    std::vector<T> configs_ {};
};

该模板类支持从文件中读取配置信息并以数组形式存储起来。可以使用宏定义CONFIG_MANAGER自动化生成不同类型的具体化类,以便支持多种配置类型。

#define CONFIG_MANAGER(class_name) \
    class ConfigManager##class_name : public ConfigManager<class_name> {\
    public: ConfigManager##class_name() {} virtual ~ConfigManager##class_name() = default; \
    }; \
    static inline auto& Get##class_name##Singleton() { \
        return Singleton<ConfigManager##class_name>::instance(); \
    }
CONFIG_MANAGER(int)
CONFIG_MANAGER(std::string)

上述代码利用了##标记来进行宏函数替换,以自动定义具体化的类名和全局函数名。

例如,CONFIG_MANAGER(int)宏展开后,生成的具体类名为ConfigManagerint,全局函数名为GetIntSingleton(),其调用方法为:

auto& config_manager_int = GetIntSingleton();
config_manager_int.load("int_config.json");
std::cout << config_manager_int.get().size() << std::endl; // 1
std::cout << config_manager_int.get()[0] << std::endl; // 10

auto& config_manager_string = GetStringSingleton();
config_manager_string.load("string_config.json");
std::cout << config_manager_string.get().size() << std::endl; // 2
std::cout << config_manager_string.get()[0] << std::endl; // abc
std::cout << config_manager_string.get()[1] << std::endl; // def

同理,CONFIG_MANAGER(std::string)生成的具体类名为ConfigManagerstd::string,全局函数名为GetStringSingleton()。由于ConfigManager类的构造函数为private,因此只能通过使用GetIntSingleton()GetStringSingleton()方法来获取其唯一实例。

4. 总结

本文介绍了如何使用宏函数实现单例模板,详细讲解了宏函数的基本生成流程,并给出了两个示例以说明其具体应用过程。单例模式具有非常重要的应用场景,掌握如何使用宏函数实现单例模板,可帮助我们在实际开发中更好地运用该设计模式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++使用宏函数实现单例模板详解 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C语言中#define定义的标识符和宏实例代码

    我来给你讲解关于C语言中#define定义的标识符和宏的完整攻略。 定义标识符 在C语言中,使用#define关键字可以定义一个标识符,并将其代表的值替换到程序中。语法如下: #define 标识符 数值或表达式 其中,标识符可以是任意字符串,而数值或表达式则可以是任意C语言表达式,例如: #define PI 3.1415926 // 将标识符PI定义为3…

    C 2023年5月30日
    00
  • 详解C++11中的线程锁和条件变量

    详解C++11中的线程锁和条件变量 C++11中提供了一系列的线程同步机制,包括线程锁和条件变量。线程锁主要是为了保护共享资源,防止多个线程同时对同一块内存区域进行操作而发生冲突;而条件变量则主要是为了线程之间的协作,当一个线程等待某个条件成立时,可以通过条件变量来阻塞当前线程,直到条件被满足为止。 线程锁 Mutex Mutex(互斥锁)是最基本的线程锁,…

    C 2023年5月22日
    00
  • C++控制台实现密码管理系统

    为了编写C++控制台实现密码管理系统,我们需要遵循以下步骤: 步骤1:设计数据结构 设计数据结构是密码管理系统的第一步,我们需要确定各种密码信息的存储方式。我们可以选择使用结构体、类或数组来存储不同的用户信息。 例如: struct Password{ char username[15]; char password[15]; char descriptio…

    C 2023年5月23日
    00
  • 基于C语言实现泛型编程详解

    基于C语言实现泛型编程详解 在C语言中实现泛型编程是一件比较困难的事情,因为C语言本身不支持泛型。但是,有一种叫做泛型指针的技术,在C语言中实现泛型编程成为了可能。 泛型指针 泛型指针是一种特殊的指针类型,它可以指向任何类型的数据。在C语言中,使用void*关键字定义泛型指针。 void* ptr; 泛型指针可以将数据类型定义为一个指针类型。例如: int …

    C 2023年5月23日
    00
  • 深入理解c++常成员函数和常对象

    以下是深入理解C++常成员函数和常对象的完整攻略: 1. 常成员函数 1.1 常成员函数的定义和声明 C++ 中的类成员函数,如果不加修饰,都可以被修改其所属对象的数据成员和调用其它成员函数。但是有时候我们希望某个成员函数只能被调用,但不能修改对象的数据成员,这个时候就需要使用常成员函数。常成员函数在函数声明的后面加上 const 关键字。 常成员函数的声明…

    C 2023年5月22日
    00
  • Django Rest framework之认证的实现代码

    下面我为您详细讲解Django Rest Framework(DRF)中实现认证的代码攻略。 1、DRF认证方式 DRF提供了多种认证方式,包括: BasicAuthentication:HTTP的基本认证方式,不安全,适用于内部系统或测试环境; TokenAuthentication:使用token实现的认证方式,适用于前后端分离项目; SessionAu…

    C 2023年5月23日
    00
  • 10分钟掌握XML、JSON及其解析

    10分钟掌握XML、JSON及其解析 什么是XML XML 是一种常用的标记语言,用于存储和传输数据。它的全称是 eXtensible Markup Language(可扩展标记语言),是一种纯文本格式,适用于不同操作系统、程序和编程语言之间的数据交换。 XML的语法规则 XML文档必须有一个根元素。 XML元素必须有一个结束标签。 XML元素必须正确嵌套。…

    C 2023年5月23日
    00
  • 系统提示lsass.exe失败状态代码c0000005的解决方法

    解决“系统提示lsass.exe失败状态代码c0000005”的方法 什么是lsass.exe? lsass.exe是Windows操作系统中的一个进程,它负责处理用户登录信息等安全相关的任务。由于其重要性,所以典型情况下,它的进程权限是系统管理员。 了解错误信息 在运行Windows操作系统时,您可能会看到一个弹出对话框,指示“lsass.exe失败,状态…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部