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

C++是否存在与TypeScript交叉类型等效的实现方案?

解决方案

C++ 没有原生的交叉类型语法,但可以通过两种主流方案实现和 TypeScript 交叉类型完全一致的效果,且不需要修改现有 Camera、SpotLight 等类的继承结构。

方案1:模板化类(编译期检查,零运行时开销)

直接将 FixedAttachment 定义为模板类,通过编译期静态检查约束传入的 tracker 类型必须同时实现两个接口,运行时无额外开销,适合绝大多数场景。

实现代码

#include <type_traits>
#include <memory>
#include <glm/glm.hpp>

// 核心:模板参数约束
template <typename TrackerT>
class FixedAttachment
{
    // 编译期校验TrackerT必须同时继承两个接口
    static_assert(
        std::is_base_of_v<Interface::Positionable, TrackerT> &&
        std::is_base_of_v<Interface::Directionable, TrackerT>,
        "Tracker must implement both Positionable and Directionable interfaces"
    );
public:
    FixedAttachment(
        std::shared_ptr<Interface::Positionable> target,
        std::shared_ptr<TrackerT> tracker,
        const glm::vec3& position
    ) : m_target(std::move(target)),
        m_tracker(std::move(tracker)),
        m_position(position)
    {}

    void updateTracker()
    {
        glm::vec3 calculatedPosition = /* 你的位置计算逻辑 */;
        glm::vec3 calculatedDirection = /* 你的方向计算逻辑 */;
        // 直接调用两个接口的方法,编译期就确认合法
        m_tracker->setPosition(calculatedPosition);
        m_tracker->setDirection(calculatedDirection);
    }

    // 其他原有方法保持不变
    std::shared_ptr<Interface::Positionable> getSharedTarget() const { return m_target; }
    Interface::Positionable* getTarget() const { return m_target.get(); }
    const glm::vec3& getPosition() const { return m_position; }

private:
    std::shared_ptr<Interface::Positionable> m_target;
    std::shared_ptr<TrackerT> m_tracker;
    glm::vec3 m_position;
};

用法示例

不需要修改任何原有类的定义,直接传入符合要求的实例即可:

// 传入Camera实例
auto camera = std::make_shared<Camera>();
auto cameraAttachment = std::make_shared<FixedAttachment<Camera>>(target, camera, pos);

// 传入SpotLight实例
auto spotLight = std::make_shared<SpotLight>();
auto lightAttachment = std::make_shared<FixedAttachment<SpotLight>>(target, spotLight, pos);

优缺点

  • 优点:零运行时开销,编译期就会报类型不匹配错误,开发体验好
  • 缺点:模板类的实现需要暴露在头文件中,不同的Tracker类型会生成少量冗余的类代码(实际场景下可忽略)

方案2:接口包装类(非模板,隐藏实现)

如果你不想用模板,希望把 FixedAttachment 的实现放到 cpp 文件中减少编译依赖,可以定义一个通用的交叉接口包装类,内部同时存储两个接口的智能指针。

实现代码

#include <type_traits>
#include <memory>
#include <glm/glm.hpp>

class PosDirTracker
{
public:
    // 通用构造函数,接收任意符合要求的类型
    template <typename T>
    PosDirTracker(std::shared_ptr<T> ptr)
        : m_posPtr(ptr), m_dirPtr(ptr)
    {
        static_assert(
            std::is_base_of_v<Interface::Positionable, T> &&
            std::is_base_of_v<Interface::Directionable, T>,
            "Type must implement both Positionable and Directionable interfaces"
        );
    }

    // 直接转发接口方法,调用更方便
    void setPosition(const glm::vec3& pos) { m_posPtr->setPosition(pos); }
    void setDirection(const glm::vec3& dir) { m_dirPtr->setDirection(dir); }
    const glm::vec3& getPosition() const { return m_posPtr->getPosition(); }
    const glm::vec3& getDirection() const { return m_dirPtr->getDirection(); }

private:
    std::shared_ptr<Interface::Positionable> m_posPtr;
    std::shared_ptr<Interface::Directionable> m_dirPtr;
};

// FixedAttachment不需要是模板类
class FixedAttachment
{
public:
    FixedAttachment(
        std::shared_ptr<Interface::Positionable> target,
        PosDirTracker tracker,
        const glm::vec3& position
    ) : m_target(std::move(target)),
        m_tracker(std::move(tracker)),
        m_position(position)
    {}

    void updateTracker()
    {
        glm::vec3 calculatedPosition = /* 位置计算逻辑 */;
        glm::vec3 calculatedDirection = /* 方向计算逻辑 */;
        m_tracker.setPosition(calculatedPosition);
        m_tracker.setDirection(calculatedDirection);
    }

    // 其他原有方法不变
private:
    std::shared_ptr<Interface::Positionable> m_target;
    PosDirTracker m_tracker;
    glm::vec3 m_position;
};

用法示例

和方案1完全一致,不需要修改原有类:

auto camera = std::make_shared<Camera>();
auto attachment = std::make_shared<FixedAttachment>(target, camera, pos);

优缺点

  • 优点:FixedAttachment不是模板类,实现可以放到cpp中,减少编译依赖
  • 缺点:每个包装类多存储一个智能指针,开销极小可忽略

C++20 优化写法

如果你使用C++20及以上版本,可以用concept替代static_assert,语法更简洁:

template <typename T>
concept PosDirCompatible = std::is_base_of_v<Interface::Positionable, T> &&
                           std::is_base_of_v<Interface::Directionable, T>;

// 模板类直接用concept约束
template <PosDirCompatible TrackerT>
class FixedAttachment {
    // 不需要再写static_assert
};

新增交叉类型需求的处理

如果后续需要Light & Interface::Directionable这类新的交叉类型,只需要复用上述逻辑,新增对应的模板约束或者包装类即可,完全不需要修改原有类的继承结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 10:00:03