在抽象基类定义中使用未知类型

时间:2019-11-05 07:16:31

标签: c++ oop

我有一个抽象基类IThingDoer和一个virtual方法doThingWithData。我想要的是让IThingDoer的具体类实现doThingWithData(&someType dat),除了dat的变量类型(即someType是什么)在不同的具体类之间变化之外。

例如:

class IThingDoer {
public:
    virtual void doThingWithData(&someType dat); //??
};

struct Foo {
    int foo1;
    double foo2;
};

class FooThingDoer : public IThingDoer {
public:
    void doThingWithData(&Foo dat){
        std::cout << dat.foo1
    }
};

struct Bar {
    float bar1[2];
};

class BarThingDoer : public IThingDoer {
public:
    void doThingWithData(&Bar dat){
        std::cout << (dat.bar1[0] + dat.bar1[1]);
    }
};

我尝试让FooBar都从另一个基本数据类继承:(我已经改变了实际情况以简化示例)

class BaseData{
public:
    int baseData = 1;
};

class IThingDoer{
public:
    virtual void doThingWithData(BaseData dat) = 0;
};

class FooData : public BaseData {
public:
    int otherData = 5;
};

class FooThingDoer : public IThingDoer {
public:
    void doThingWithData(BaseData dat){
        std::cout << dat.otherData;
    }
};

int main()
{
    FooThingDoer a = FooThingDoer();
    FooData dat = FooData();
    a.doThingWithData(dat);

    return 0;
}

但是,这不起作用-编译器找不到dat.otherData,因为otherData类型中没有BaseData。在BaseData中将FooData更改为FooThingDoer.doThingWithData也不起作用,因为这只会导致其重载名称,而实际上并未在IThingDoer中实现虚函数。

我也看过模板,但是(从一个相对缺乏经验的程序员的角度来看),看起来模板似乎主要用于减少对每种可能类型的重载函数的需求。

需要明确的是,未知数据类型仅是抽象类所未知;它们将在编译时被知道。

有没有办法解决这个问题?


附录:我可能正在处理XY问题;因此,我在这里添加了一些其他上下文。

从更大的角度看,此代码将在不同的硬件上运行,具有不同的传感器和需要控制的东西。不同的ThingDoer实现了需要发生的特定功能,但是在所有情况下,每个ThingDoer都可以被视为黑匣子,该黑匣子将某些数据结构作为输入,并执行一些操作作为输出,并且特定的输入数据结构在不同的ThingDoers之间变化

据我了解,为了提高程序其余部分的代码重用性,每个ThingDoer应该从描述此黑匣子功能的抽象类继承,其余代码应与此接口一起工作。我计划让单独的对象准备ThingDoer用作输入的实际数据结构。同样,每种硬件类型我都会有一个准备器对象。

然后,根据我要编译的硬件,我将在编译中包括不同的头文件(包含我需要的特定ThingDoer等)。由于在编译时会使用特定的ThingDoer和相应的输入准备器,因此我认为这些类型将在编译时已知,因此没有任何动态类型。

1 个答案:

答案 0 :(得分:1)

您可以将模板用于静态多态性。

#include <iostream>


template <class T>
class IThingDoer {
public:
    virtual void doThingWithData(T dat) = 0;
};

struct Foo {
    int foo1;
    double foo2;
};

class FooThingDoer : public IThingDoer<Foo> {
public:
    void doThingWithData(Foo dat) {
        std::cout << dat.foo1;
    }
};

struct Bar {
    float bar1[2];
};

class BarThingDoer : public IThingDoer<Bar> {
public:
    void doThingWithData(Bar dat) {
        std::cout << (dat.bar1[0] + dat.bar1[1]);
    }
};

int main()
{
    FooThingDoer a = FooThingDoer();
    Foo foo;
    foo.foo1 = 5;
    foo.foo2 = 5.5;
    a.doThingWithData(foo);
    return 0;
}

但是您的示例也可以使用(u只能转换地址,而不能转换静态对象):

#include <iostream>

class BaseData {
public:
    int baseData = 1;
};

class IThingDoer {
public:
    virtual void doThingWithData(BaseData& dat) = 0;
};

class FooData : public BaseData {
public:
    int otherData = 5;
};

class FooThingDoer : public IThingDoer {
public:
    void doThingWithData(BaseData& dat) {
        std::cout << ((FooData&) dat).otherData;
    }
};

int main()
{
    FooThingDoer a = FooThingDoer();
    FooData dat = FooData();
    a.doThingWithData(dat);

    return 0;
}