模板,前向声明,dll

时间:2020-11-09 22:38:14

标签: c++

这与应用程序的以下设置有关,该应用程序使用* .dll和静态库中的(抽象)功能,并最终导致读取访问冲突(代码下方提供了更多详细信息):

...静态库...

// InterfaceWrap.h 
//-----------

// dummy include
#include <SomeTClass.h>

template<typename T>
class InterfaceWrap
{
    std::shared_ptr<SomeTClass<T>> m_somePtr;
    public:
        InterfaceWrap();
        ~InterfaceWrap();
        void AnyAction();
};

template<typename T>
InterfaceWrap<T>::InterfaceWrap() {
    m_somePtr = std::make_shared<SomeTClass<T>>();
}

template<typename T>
void InterfaceWrap<T>::AnyAction() {
    m_somePtr->SomeAction();
}

... * .dll ...

// Proc.h 
//-----------

// correct forward declaration?
class ThisInterface;

#include <InterfaceWrap.h>

class DLL Proc
{
    std::shared_ptr<InterfaceWrap <ThisInterface>> m_interfaceWrapPtr;
    public:
        Proc();
        ~Proc();
        InterfaceWrap<ThisInterface>* GetPtr();
};

// Proc.cpp 
//-----------

// what about forward declaration here?
Proc::Proc() {
    m_interfaceWrapPtr = std::make_shared<InterfaceWrap<ThisInterface>>();
}

InterfaceWrap<ThisInterface>* Proc::GetPtr() {
    return m_interfaceWrapPtr.get();
}

...应用程序...

// main.cpp
//-----------
#include <Proc.h>

// dummy includes
#include <ThisType01.h>
#include <ThisType02.h>
#include <ThisType11.h>
#include <ThisType12.h>

class ThisInterfaceA {
    public:
    using Type1 = ThisType01;
    using Type2 = ThisType02;
};

class ThisInterfaceB { // not needed here but perhaps illustrative
    public:
    using Type1 = ThisType11;
    using Type2 = ThisType12;
};

using ThisInterface = ThisInterfaceA;

int main(int argc, char * argv[])
{
    Proc proc;
    proc.GetPtr()->AnyAction();
    return 0;
}

此构造背后的关键意图是使ProcInterfaceWrap类保持尽可能抽象,即使它们不直接依赖于所选的“接口”(例如ThisInterfaceA)。此外,我想保留该功能,即Proc不是模板类。

显然存在问题,但我不确定如何很好地解决它们:

  1. using ThisInterface = ThisInterfaceA行不起作用,因为它导致dll源代码的编译错误,基本上是说ThisInterface是未知的。但是,如果直接用ThisInterfaceA代替ThisInterface而不是这一行,则所有编译和链接都至少可以正常进行。
  2. 即使所有内容都进行了编译和链接(比较1.),最终仍将发生涉及m_interfaceWrapPtrm_somePtr的读取访问冲突。

我特别想知道的是,正确应用的前向声明是否能够解决上述问题,并允许保留Proc是抽象(甚至更多)而不是模板类的功能? / p>

2 个答案:

答案 0 :(得分:0)

为什么不使用真实界面和DIP

struct IAnyAction
{
    virtual ~IAnyAction() = default;
    virtual void AnyAction() = 0;
};

class Proc
{
    std::shared_ptr<IAnyAction> m_interface;
public:
    Proc(std::shared_ptr<IAnyAction> anyAction) : m_interface(anyAction) {}

    IAnyAction* GetPtr() { return m_interface.get(); }
};
template<typename T>
class InterfaceWrap : public IAnyAction
{
    std::shared_ptr<SomeTClass<T>> m_somePtr;
public:
    InterfaceWrap();
    void AnyAction() override { m_somePtr->SomeAction(); }
};

using ThisInterface = ThisInterfaceA; // For easy/quick way to change concrete type for interface

int main()
{
    Proc proc(std::make_shared<InterfaceWrap<ThisInterface>>());

    proc.GetPtr()->AnyAction();
}

答案 1 :(得分:0)

万一有兴趣的人,下面提供了经过修改的示例代码(从头开始),因为它最终对我有用。 解决方案基本上是answer of Jarod42(也许其他评论中指出的那样,这种总体方法可能不是最优雅的方法。但是,我认为某些目的可能是合理的)。

但是,添加了一点小东西:强制转换指针指针参数。对我来说,这在将原始问题扩展到例如成员AnyAction且其参数尚未确定但为“已知”类型时很有用。

...静态库...

// InterfaceWrap.h 
//-----------

// dummy include
#include <SomeTClass.h>

struct IAnyAction
{
    virtual ~IAnyAction() = default;
    virtual void AnyAction(void* arg) = 0;
};

template<typename T>
class InterfaceWrap : public IAnyAction
{
    std::shared_ptr<SomeTClass<T>> m_somePtr;
    public:
        InterfaceWrap();
        void AnyAction(void* arg);
};

template<typename T>
InterfaceWrap<T>::InterfaceWrap(){
    m_somePtr = std::make_shared<SomeTClass<T>>();
}

template<typename T>
void InterfaceWrap<T>::AnyAction(void* arg) override {
    auto thisArg = static_cast<T::Type1*>(arg);
    m_somePtr->SomeAction(*thisArg);
}

... * .dll ...

// Proc.h 
//-----------

#include <InterfaceWrap.h>

class DLL Proc
{
    std::shared_ptr<IAnyAction> m_interfaceWrapPtr;
    public:
        Proc(std::shared_ptr<IAnyAction> interfaceWrapPtr);
        ~Proc();
        IAnyAction* GetPtr();
};

// Proc.cpp 
//-----------

Proc::Proc(std::shared_ptr<IAnyAction> interfaceWrapPtr) : m_interfaceWrapPtr(interfaceWrapPtr) {
}

IAnyAction* Proc::GetPtr() {
    return m_interfaceWrapPtr.get();
}

...应用程序...

// main.cpp
//-----------
#include <Proc.h>

// dummy includes
#include <ThisType01.h>
#include <ThisType02.h>
#include <ThisType11.h>
#include <ThisType12.h>

class ThisInterfaceA {
    public:
    using Type1 = ThisType01;
    using Type2 = ThisType02;
};

class ThisInterfaceB { // not needed here but perhaps illustrative
    public:
    using Type1 = ThisType11;
    using Type2 = ThisType12;
};

using ThisInterface = ThisInterfaceA;

int main(int argc, char * argv[])
{
    Proc proc(std::make_shared<InterfaceWrap<ThisInterface>>());
    auto type1 = std::make_shared<ThisInterface::Type1*>();
    proc.GetPtr()->AnyAction(type1.get());
    return 0;
}