You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

导出继承sf::Drawable的类时无法在std::vector中使用的问题

解决动态库导出含自引用vector的SFML Entity类时的C2672编译错误

问题场景

使用SFML开发2D游戏引擎,将引擎从静态库转为动态库时,给继承sf::Transformable和sf::Drawable的Entity类添加__declspec(dllexport)后,因类内包含std::vector<Entity>成员,编译报错C2672: 'std::construct_at': 找不到匹配的重载函数,静态库模式下无此问题。

相关代码

Test.h

#pragma once

#include <SFML/Graphics.hpp>
#include <vector>
#include <memory>

class __declspec(dllexport) Entity : sf::Transformable, sf::Drawable
{
public:
    Entity()
    {
    };

    ~Entity()
    {
    };

public:
    std::vector<Entity> children;
};

Test.cpp

#include "Test.h"

错误信息

1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\xmemory(698,14): error C2672: 'std::construct_at': no matching overloaded function found
1>(compiling source file '/Window.cpp')
1>    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\xutility(388,16):
1>    could be '_Ty *std::construct_at(_Ty *const ,_Types ...) noexcept(<expr>)'
1>    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\xmemory(698,14):
1>    the template instantiation context (the oldest one first) is
1>        C:\Users\jehud\source\repos\Harmony\Harmony\Test.h(19,22):
1>        see reference to class template instantiation 'std::vector<Entity,std::allocator<Entity>>' being compiled
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\vector(1476,26):
1>        while compiling class template member function 'std::vector<Entity,std::allocator<Entity>> &std::vector<Entity,std::allocator<Entity>>::operator =(const std::vector<Entity,std::allocator<Entity>> &)'
1>            C:\Users\jehud\source\repos\Harmony\Harmony\Test.h(20,1):
1>            see the first reference to 'std::vector<Entity,std::allocator<Entity>>::operator =' in 'Entity::operator ='
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\vector(1492,9):
1>        see reference to function template instantiation 'void std::vector<Entity,std::allocator<Entity>>::_Assign_counted_range<Entity*>(_Iter,const unsigned __int64)' being compiled
1>        with
1>        [
1>            _Iter=Entity *
1>        ]
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\vector(1395,32):
1>        see reference to function template instantiation 'Entity *std::_Uninitialized_copy_n<Entity*,std::allocator<Entity>>(_InIt,size_t,Entity *,_Alloc &)' being compiled
1>        with
1>        [
1>            _InIt=Entity *,
1>            _Alloc=std::allocator<Entity>
1>        ]
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\xmemory(1865,18):
1>        see reference to function template instantiation 'void std::_Uninitialized_backout_al<std::allocator<Entity>>::_Emplace_back<Entity&>(Entity &)' being compiled
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.41.34120\include\xmemory(1779,35):
1>        see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,Entity&>(_Alloc &,_Objty *const ,Entity &)' being compiled
1>        with
1>        [
1>            _Alloc=std::allocator<Entity>,
1>            _Ty=Entity,
1>            _Objty=Entity
1>        ]

核心原因

  1. 私有继承基类:C++中class默认私有继承,导致sf::Transformable和sf::Drawable的构造/拷贝构造函数无法被标准库函数(如std::construct_at)访问,因为这些函数属于外部代码,无权访问私有基类的成员。
  2. 未实现抽象基类纯虚函数:sf::Drawable是抽象基类,必须实现draw()纯虚函数,否则Entity属于抽象类,无法被实例化(而std::vector<Entity>需要创建Entity对象)。
  3. 动态库导出的默认拷贝操作冲突:添加__declspec(dllexport)后,编译器生成的默认拷贝构造/赋值运算符的导出标记与基类的访问权限冲突,触发模板实例化时的构造函数匹配失败。

解决方案

1. 改为公有继承基类

将Entity对SFML基类的继承改为公有继承,确保外部代码能正确访问基类的构造逻辑:

class ENGINE_API Entity : public sf::Transformable, public sf::Drawable

2. 实现sf::Drawable的纯虚函数

必须实现draw()函数,使Entity成为可实例化的具体类:

virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override {
    states.transform *= getTransform();
    for (const auto& child : children) {
        target.draw(child, states);
    }
}

3. 使用导出/导入宏区分编译场景

定义宏避免动态库导出和导入时的重复标记问题,在动态库工程中添加ENGINE_EXPORTS预处理器定义:

#ifdef ENGINE_EXPORTS
#define ENGINE_API __declspec(dllexport)
#else
#define ENGINE_API __declspec(dllimport)
#endif

4. 显式定义拷贝构造和赋值运算符

显式实现这些操作,确保基类的拷贝逻辑被正确调用,同时保证函数能被动态库正确导出:

Entity(const Entity& other) 
    : sf::Transformable(other), 
      sf::Drawable(other), 
      children(other.children) {}

Entity& operator=(const Entity& other) {
    if (this != &other) {
        sf::Transformable::operator=(other);
        sf::Drawable::operator=(other);
        children = other.children;
    }
    return *this;
}

修改后的完整代码

Test.h

#pragma once

#include <SFML/Graphics.hpp>
#include <vector>

#ifdef ENGINE_EXPORTS
#define ENGINE_API __declspec(dllexport)
#else
#define ENGINE_API __declspec(dllimport)
#endif

class ENGINE_API Entity : public sf::Transformable, public sf::Drawable
{
public:
    Entity() = default;
    ~Entity() = default;

    Entity(const Entity& other) 
        : sf::Transformable(other), 
          sf::Drawable(other), 
          children(other.children) {}

    Entity& operator=(const Entity& other) {
        if (this != &other) {
            sf::Transformable::operator=(other);
            sf::Drawable::operator=(other);
            children = other.children;
        }
        return *this;
    }

    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override {
        states.transform *= getTransform();
        for (const auto& child : children) {
            target.draw(child, states);
        }
    }

public:
    std::vector<Entity> children;
};

Test.cpp

#include "Test.h"

内容的提问来源于stack exchange,提问作者J3hud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:55:54