c++ 在函数指针的输入和输出中使用多态性

ct3nt3jp  于 2023-01-22  发布在  其他
关注(0)|答案(1)|浏览(120)

我学习了多态性的概念,并尝试使用这个概念来创建一个名为“管道”的Map,它接受输入向量(其思想是这些可以是不同的数据结构)并应用于输入函数(在不同的用例中也可以不同地选择该函数)并且产生结果向量(也会因情况而异)。我的想法是尝试以下操作

#include <iostream>
#include <vector>

using namespace std;

struct input
{
};

struct intInput : public input
{
    intInput(int x) :x(x) {}
    int x;
};

struct result
{
};

struct intResult : public result
{
    intResult(int y) :y(y) {}
    int y;
};

vector<result> pipeline(vector<input> x, result(*g)(input))
{
    std::vector<result> res;
    for (size_t i = 0; i < x.size(); i++)
    {
        res.push_back((*g)(x[i]));
    }
    return res;
}

intResult doubling(intInput i)
{
    intResult res(2 * i.x);
    return res;
}

void printing(input i)
{
    cout << "hi" << endl;
}

int main()
{
    vector<intInput> v{ 1,2,3,4 };
    pipeline(v, doubling);
}

但我得到了编译错误

'std::vector<result,std::allocator<result>> pipeline(std::vector<input,std::allocator<input>>,result (__cdecl *)(input))': cannot convert argument 1 from 'std::vector<intInput,std::allocator<intInput>>' to 'std::vector<input,std::allocator<input>>'

有什么办法可以解决这个问题吗?

k3bvogb1

k3bvogb11#

vector<input>vector<intInput>不是多态的,并且永远不会是-vector<input>知道每个条目是1字节长(最小大小),并且vector<intInput>知道每个条目是4字节长。
但是,您可以通过将pipeline设置为模板来实现所需的功能,例如:

template<typename MyResult, typename MyInput>
vector<MyResult> pipeline(vector<MyInput> x, MyResult(*g)(MyInput))
{
    std::vector<MyResult> res;
    for (size_t i = 0; i < x.size(); i++)
    {
        res.push_back((*g)(x[i]));
    }
    return res;
}

不需要继承。你可以删除类inputresult。编译器将能够根据需要生成这个函数的变体,如下所示:

vector<intResult> pipeline<intInput, intResult>(vector<intInput> x, intResult(*g)(intInput))
vector<int> pipeline<int, int>(vector<int> x, int(*g)(int))
vector<string> pipeline<float, string>(vector<float> x, string(*g)(float))

您可以将该函数作为pipeline<intInput, intResult>(v, doubling);调用,但也可以在编译器能够自行解决<>部分时省略它,这样您就可以调用pipeline(v, doubling);
注意,如果你在头文件中声明了这个函数,那么它的定义也应该在同一个头文件中,而不是在.cpp文件中,因为每次编译器看到你调用这个函数时,它必须为那个调用创建正确的函数版本,因此它必须知道函数中有什么代码。

  • 从技术上讲,它是一个函数模板,而不是函数

C++中的继承多态性只适用于指针或引用。这是因为所有指针的大小都相同。处理input*的代码不必关心在input末尾后面实际上有一些它不知道的额外变量。(除非它使用指针算法!指针算法不是多态的)
你可以有一个指针向量(vector<input*>),但这通常有点笨拙,或者你可以做一些返回指针的东西:(此处使用指针完成,但也可以使用引用)

struct inputGetter {
    virtual input* getInputPointer(int index) = 0;
    virtual size_t size() = 0;
};

struct intInputVectorGetter : public inputGetter {
    vector<intInput>* theVector;
    intInputVectorGetter(vector<intInput>* theVector) {
        this->theVector = theVector;
    }
    input* getInputPointer(int index) override {
        return &theVector[index];
    }
    size_t size() override {
        return theVector.size();
    }
};

// make a resultSetter, too

void pipeline(resultSetter* y, inputGetter* x, void(*g)(output*, input*)) {
    y->clear();
    y->setSize(x->size());
    for (size_t i = 0; i < x->size(); i++)
    {
        (*g)(y->getResultPointer(i), x->getInputPointer(i));
    }
}

正如你所看到的,为了防止pipeline函数处理任何实际的结果对象--只有指针--它实际上是丑陋的。对于这个pipeline函数,模板解决方案确实更好。

相关问题