一、背景

    1. factory.h
#pragma once
#include <map>
#include <iostream>
#include <string>
#include <functional>
#include <memory>class Message
{public:virtual ~Message() {}virtual void foo(){}
};struct factory
{template<typename T>struct register_t{register_t(const std::string& key){factory::get().map_.emplace(key, [] { return new T(); });}template<typename... Args>register_t(const std::string& key, Args... args){factory::get().map_.emplace(key, [&] { return new T(args...); });}};static Message* produce(const std::string& key){if (map_.find(key) == map_.end())throw std::invalid_argument("the message key is not exist!");return map_[key]();}static std::unique_ptr<Message> produce_unique(const std::string& key){return std::unique_ptr<Message>(produce(key));}static std::shared_ptr<Message> produce_shared(const std::string& key){return std::shared_ptr<Message>(produce(key));}private:factory() {};factory(const factory&) = delete;factory(factory&&) = delete;static factory& get(){static factory instance;return instance;}static std::map<std::string, std::function<Message*()>> map_;
};std::map<std::string, std::function<Message*()>> factory::map_;#define REGISTER_MESSAGE_VNAME(T) reg_msg_##T##_
#define REGISTER_MESSAGE(T, key, ...) static factory::register_t<T> REGISTER_MESSAGE_VNAME(T)(key, ##__VA_ARGS__);
  • 2.message.h
#pragma once
#include "factory.h"class Message1 : public Message
{public:Message1(){std::cout << "message1" << std::endl;}Message1(int a){std::cout << "message1" << std::endl;}~Message1(){}void foo() override{std::cout << "message1" << std::endl;}
};//REGISTER_MESSAGE(Message1, "message1", 2);
REGISTER_MESSAGE(Message1, "message1");
    1. main.cc
#include "message.h"int main()
{Message* p = factory::produce("message1");p->foo();   //Message1auto p2 = factory::produce_unique("message1");p2->foo();  return 0;
}

运行没有问题。

二、问题

当我把message.h分成两个文件:message.hmessage.cc时:

  • 2.1 message.h
class Message
{public:virtual ~Message() {}virtual void foo(){}
};#include "factory.h"class Message1 : public Message
{public:Message1(){std::cout << "message1" << std::endl;}Message1(int a){std::cout << "message1" << std::endl;}~Message1(){}void foo() override;
};//REGISTER_MESSAGE(Message1, "message1", 2);
REGISTER_MESSAGE(Message1, "message1");
  • 2.2 message.cc
#include "message.h"
void Message1::foo() {std::cout << "message1" << std::endl;
}

编译时报错:

三、原因

由于factory.h中有一个变量定义:

std::map<std::string, std::function<Message*()>> factory::map_;

当程序编译时,message.hmessage.cc都会调用一次factory.h,这样会导致多次编译上面这句代码,造成重复定义错误。

所以,当头文件中存在一个定义语句时要特别注意。

四、解决方法

新建factory.cc,把变量定义的代码从h文件中删除,放到cc文件下:

#include "factory.h"
std::map<std::string, std::function<Message*()>> factory::map_;

致谢

谢谢建哥!

[轻笔记]C++实现类自注册时出现“multiple definition”(重定义)错误相关推荐

  1. java双目运算符重载,c++类的单目和双目运算符的重定义

    这个里面需要注意的是对于双目运算符,像是加号,如果是复数加整数是一种情况,而整数加复数又是另一种情况,所以需要重定义两次. 而对于单目运算符,如果是前缀的,直接重定义就可以了,但是如果是后缀的,我们在 ...

  2. testbed笔记:基类或者成员对象的构造函数调用问题

    testbed笔记:基类或者成员对象的构造函数调用问题@TOC testbed笔记:基类或者成员对象的构造函数调用问题 testbed在run driver时候报错: 错误1 找不到基类构造函数 错误 ...

  3. 问题记录:multiple definition of `xxxx` 问题解决 struct定义类的error:“unknown type name“

    一.multiple definition of xxxx 问题解决 问题背景 我在一个头文件里面定义了一个变量,并赋予初值,然后再两个.c 文件里引入了这个头文件,结果就报错 multiple de ...

  4. 在类中用class时数据是共有还是私有_jvm学习笔记之class文件的加载、初始化

    编写的java文件在要真正运行时,会首先被编译成 ".class"结尾的二进制文件,然后被虚拟机加载.那么在虚拟机中一个class文件要成为java实例,需要经历好几个步骤: 1. ...

  5. 轻笔记显示无法连接到服务器,轻笔记:支持群组的跨平台笔记应用 (1)PC客户端...

    [摘要]支持群组协作.本文为系列文章的第一篇,细致介绍了其PC客户端的功能.特点,尤其是群组协作功能. [说明]①本文是善用佳软网站的第一篇收费文章,轻笔记官方为此宣传支付了一定费用.②在与轻笔记团队 ...

  6. 窗口类的注册生成和消息循环

    1.一个项目只有一个子类继承cWinApp类,该子类也只有一个全局的对象,系统初始化时先运行 这个全局对象的构造函数及父类的构造函数 2.运行WinMain函数,调用AfxWinMain函数 3.运行 ...

  7. Python3 基础学习笔记 C08 【类】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

  8. Kotlin学习笔记 第二章 类与对象 第一节类与继承(补)

    参考链接 Kotlin官方文档 Kotlin docs | Kotlin 本系列为参考Kotlin中文文档 kotlin官方文档2020版.pdf-其它文档类资源-CSDN下载 第二章 第一节 类与继 ...

  9. 【java笔记】File类(2):获取,判断,创建,删除,遍历目录方法

    [java笔记]File类(1)概述,静态成员,构造方法_m0_52043808的博客-CSDN博客 获取功能方法: public String getAbsolutePath():返回此File的绝 ...

最新文章

  1. 容器环境红队手法总结
  2. Hbase API中常用类介绍和使用
  3. 单防区扩展模块怎么用_Zens推出模块化可扩展无线充电器 可为6台设备同时供电...
  4. 灰度图的width和widthstep的区别
  5. 大学计算机基础知识判断题,大学计算机基础学习知识判断题.doc
  6. 【Day12】整个前端性能提升大致分几类
  7. 浅谈BP神经网络的Matlab实现
  8. [HNOI2008]水平可见直线 半平面交
  9. 【早报】这届程序员要做好会Python的准备了!
  10. 购物商城Web开发第十天
  11. 解决keil5不支持Samsung 2440A等较旧型号Soc的方法
  12. 二、SSD网络原理及代码讲解
  13. Can't update 分支名 has no tracked branch
  14. IC面试常考题 Verilog三分频电路设计(占空比50%,三分之一,三分之二)
  15. win10家庭版调出组策略(gpedit.msc)要求的函数不受支持
  16. 机器学习 数学基础 学习笔记 (1) 导数
  17. Effective JavaScript Item 23 永远不要修改arguments对象
  18. 《荒野大镖客》:从西部世界构建到资本社会现象
  19. 弗莱纳公式(Frenet–Serret formulas)
  20. 符咒AA4属性转移模块

热门文章

  1. Linux桌面虚拟化技术-KVM
  2. 这可能是最非主流的斯坦·李纪念方式。论编程语言与超级英雄的联系
  3. 网站如何部署到阿里云服务器教程
  4. 山西省2019年中考计算机试题,2019山西中考信息技术试题命题说明
  5. 电路与电子线路实验二-mutisim仿真实验——北京理工大学
  6. 低代码开发和无代码开发有什么区别?
  7. Android RecyclerView TV-滑动选中态背景
  8. linux实验六vi文本编辑器,Linux-实验六-vi文本编辑器.docx
  9. Dev-c++编写 数字华容道
  10. (原创)vue-cli3引入google地图 —— 自己坑自己填