在C++中“粘合”两个类实现的正确方法

eqfvzcg8  于 2023-03-05  发布在  其他
关注(0)|答案(3)|浏览(153)

我是C++新手,现在我有一个问题需要解决。我在A库中有一个类,在B库中有一个类,C函数是A和B之间的唯一连接,我需要传递在A中实现的类,并在B中运行它,在C函数中最好的方法是什么?在A库中

class ClassAImp : public ClassA
{
public:
    ClassAImp();
    ~ClassAImp();
    
    void Setup() override {/* do some setup */};
    void TearDown() override {/* do teardown stuff */};
    void runMethodA(void* ptr) override {/* do method A stuff */};
}

class ClassA
{
public:    
    virtual void Setup() = 0;
    virtual TearDown() = 0;
    virtual runMethodA(void* ptr) = 0;
}

在图书馆B

class ClassB
{
public:    
    virtual void Setup() = 0;
    virtual TearDown() = 0;
    virtual runMethodA(void* ptr) = 0;
}

现在我在C语言中做的是

class ClassBImp : public ClassB
{
public:
    ClassBImp(std::shared_ptr<ClassA> _classAObj) : classAObj(_classAObj) {};
    virtual ~ClassBImp();
    
    void Setup() override { if (classAObj) classAObj->Setup(); };
    void TearDown() override { if (classAObj) classAObj->TearDown(); };
    void runMethodA(void* ptr) override { if (classAObj) classAObj->runMethodA(ptr); };
private:
    std::shared_ptr<ClassA> classAObj;
}

并将ClassBImpPtr(作为std::shared_ptr)传递给B库。
我对库A或B没有任何控制权,只能在C中执行操作,并将实现的对象传递回B。这是在C++中执行操作的正确方法吗(11?)有更好的方法吗?

vmdwslir

vmdwslir1#

因为您得到的是一个已经构造好的ClassAImpl对象,所以这差不多是它得到的最好结果。

wqsoz72f

wqsoz72f2#

最好的情况是库A和库B使用类型擦除,这样它们就可以接受任何没有继承的类型。
如果你不能做到这一点,你可以为库编写适配器:

template<typename T>
struct AdaptatorClassA : ClassA {
    AdaptatorClassA(T object) : object{std::move(object)} {}
    
    void Setup() override {
        object.Setup();
    }

    void TearDown() override {
        object.TearDown();
    }

    void runMethodA(void* ptr) override {
        object.runMethodA(ptr);
    }

private:
    T object;
};

template<typename T>
auto makeAdaptatorClassA(T obj) -> AdaptatorClassA {
    return AdaptatorClassA<T>{std::move(obj)};
}

template<typename T>
struct AdaptatorClassB : ClassB {
    AdaptatorClassB(T object) : object{std::move(object} {}
    
    void Setup() override {
        object.Setup();
    }

    void TearDown() override {
        object.TearDown();
    }

    void runMethodA(void* ptr) override {
        object.runMethodA(ptr);
    }

private:
    T object;
};

template<typename T>
auto makeAdaptatorClassB(T obj) -> AdaptatorClassB {
    return AdaptatorClassB<T>{std::move(obj)};
}

然后使用这个函数,你可以让任何类型使用ClassB,只要该类型声明了3函数:

struct MyClassThatWorksWithBoth { // <==== No inheritance, use adaptators
    void Setup() {/* do some setup */}
    void TearDown() {/* do teardown stuff */}
    void runMethodA(void*) {/* do method A stuff */}
};

然后,您可以使用适配器将该类型发送到两个库:

auto C() -> void {
    auto c = MyClassThatWorksWithBoth{};

    auto a = makeAdaptatorClassA(c);
    auto b = makeAdaptatorClassB(c);

    // call library A and library B with both a and b
}

当然,如果需要,您可以让适配器包含指针,以便将MyClassThatWorksWithBoth的同一个示例发送到两个库。
请注意,使用适配器时,您不需要使type具有多重继承。

pgpifvop

pgpifvop3#

我想您可能对代码重复(愚蠢的重复!)感到不快。有些重复在委托中是不可避免的(这里:让一个现有的实现-ClassBImp-做另一个接口的-ClassA的-工作)。
但是,如果你只是简单地从接口和实现继承,你就不必创建一个单独的ClassAImp对象--你的类 * 是-a * ClassB--,而且转发也可以说更简单,因为你只需要用实现类名来限定你调用来做这项工作的函数:

struct ClassBImp: public ClassAImp, public ClassB
{
    void Setup() override { ClassAImp::Setup(); }
    void TearDown()  override { ClassAImp::TearDown(); }
    void runMethod(void* ptr)  override { ClassAImp::runMethod(ptr); }
};

再简单不过了。
让我们假设库B中的一个函数需要一个指向ClassB的共享指针(并且我进一步假设这个函数很可能调用我们传递指针到的ClassB对象的成员函数):

static void Library_B_Callback(std::shared_ptr<ClassB> bPtr) 
{ 
    std::cout << "DoSomething<std::shared_ptr<ClassB>>\n"; 
    if (bPtr)
    {
        std::cout << "DoSomething<std::shared_ptr<ClassB>>: Calling bPtr->runMethod()\n";
        // do something with that pointer
        bPtr->runMethod(nullptr);
    }
}

然后你可以用

int main()
{
    Library_B_Callback(make_shared<ClassBImp>());
}

也就是说,当需要指向base的共享指针时,可以提供指向派生的共享指针,就像常规指针一样;它们是协变的。

相关问题