一、背景

    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. GetLastError 函数返回值大全
  2. 【Linux入门到精通系列讲解】内存管理malloc和free函数
  3. EJBCA使用之注册用户及创建证书
  4. MacFetionV0.8.0测试版
  5. (54)FPGA条件选择有优先级(if-else)
  6. arm 饱和指令_ARM内核全解析,从ARM7,ARM9到CortexA7,A8,A9,A12,A15到CortexA53,A57
  7. 计算机基础知识背诵口诀,内部资料--教育基础知识背诵口诀(一遍记住)
  8. anaconda新建环境_机器学习实战-开发环境安装
  9. Weblogic开启managed server报错java.lang.OutOfMemoryEr
  10. html左边图片右边文字_有了这些网站,不用PS也可以做出文字云效果
  11. python第三方库的安装方式_Python第三方库的几种安装方式(小结)
  12. c51单片机矩阵键盘1602计算器_基于AT89C51单片机的十进制计算器系统设计
  13. 断网重启路由器就好_电脑老断网重启就好怎么解决
  14. 微信公众号开发:素材管理(临时、永久)
  15. 弗吉尼亚理工计算机科学排名,弗吉尼亚理工大学专业排名
  16. mysql like查询很慢_MySQL Like模糊查询速度慢的解决方法
  17. H5电玩城源码+玩法比较多+UI也特别好看+纯源码系列
  18. gluster集群服务器IP地址更改后导致服务无法启动的一个解决方法
  19. Markov链:初始概率、绝对概率
  20. linux skyeye,在Ubuntu 10.04上安装SkyEye及测试

热门文章

  1. 3d 数学(叉乘、四元素、四元素旋转、四元素和四元素相乘、鼠标控制物体旋转、发射子弹、环形发射子弹、子弹缓冲池)
  2. mysql实验四数据库查询和视图_实验四 数据库查询和视图.doc
  3. UML各种图总结精华
  4. docker到底是什么?有什么用?
  5. 零基础搭建成语小程序
  6. Go语言之sync.Pool
  7. 阿里云云计算ACP学习(三)---对象存储OSS
  8. QFP、LQFP、TQFP、FQFP封装的区别
  9. 路由器中继, 网络时常中断,问题原因及解决方案
  10. 2018-2019-2 20189215 《网络攻防技术》第五周作业