C++ vector<Data> to vector<IData>



我在C++中遇到问题,如何将vector<Data>隐式转换为vector<IData>

我对此唯一的答案是创建一个新vector<IData>并复制vector<Data>的每个元素。

我想知道C++是否有优雅的解决方案来解决此类案件。

这是代码:

#include <iostream>
#include <vector>
using namespace std;
class IData
{
    public:
        virtual int getNumber() = 0;
};
class DataA : public IData
{
    public:
        DataA(int value) : _value(value) { }
        virtual int getNumber() override
        {
            return _value;
        }
    private:
        int _value = 0;
};
class DataB : public IData
{
    public:
        DataB(int value) : _value(value) { }
        virtual int getNumber() override
        {
            return _value;
        }
    private:
        int _value = 0;
};
int calculateDataSum(vector<IData> datas)
{
    int sum;
    for (int i = 0; i < datas.size(); i++)
    {
        sum += datas[i].getNumber();
    }
    return sum;
}
int main()
{
    DataA dA0(10);
    DataA dA1(20);
    DataB dB0(100);
    DataB dB1(200);
    vector<DataA> datasA;
    datasA.push_back(dA0);
    datasA.push_back(dA1);
    vector<DataB> datasB;
    datasB.push_back(dB0);
    datasB.push_back(dB1);
    int resultA = calculateDataSum(datasA);
    int resultB = calculateDataSum(datasB);
    cout << resultA << endl;
    cout << resultB << endl;
    return 0;
}

由于您已经有一个带有虚拟方法的基类,因此最明显的方法是使用 std::vector<std::unique_ptr<IData>>

#include <memory>
int calculateDataSum(vector<std::unique_ptr<IData>>& datas)
{
    int sum;
    for (auto& data : datas)
    {
        sum += data->getNumber();
    }
    return sum;
}
int main()
{
    vector<std::unique_ptr<IData>> datasA;
    datasA.push_back(std::unique_ptr<IData>(new DataA(10)));
    datasA.push_back(std::unique_ptr<IData>(new DataA(20)));
    vector<std::unique_ptr<IData>> datasB;
    datasB.push_back(std::unique_ptr<IData>(new DataB(30)));
    datasB.push_back(std::unique_ptr<IData>(new DataB(40)));
    int resultA = calculateDataSum(datasA);
    int resultB = calculateDataSum(datasB);
    cout << resultA << endl;
    cout << resultB << endl;
    return 0;
}

使用这种方法,您还可以混合,因此您可以获得一个同时包含DataADataB的向量。

从C++类型系统的角度来看,无论DataIData层次结构关系如何,vector<Data>vector<IData>都是完全不同的类型。

问题的解决方案之一是基于模板的临时多态性:

template<typename T>
int calculateDataSum(vector<T> datas)
{
    static_assert(std::is_base_of<IData, T>::value);
    int sum;
    for (int i = 0; i < datas.size(); i++)
    {
        sum += datas[i].getNumber();
    }
    return sum;
}

请注意static_assert行。这不是必需的,但它将允许的矢量元素限制为IData的 chilren

vector<DataA>vector<DataB>元素复制到vector<IData>中将不起作用,因为它会遭受对象切片的影响。 您需要改用vector<IData*>来允许多态性正常工作,例如:

int calculateDataSum(const vector<IData*> &datas)
{
    int sum = 0;
    for (auto d : datas)
    {
        sum += d->getNumber();
    }
    return sum;
}
int main()
{
    DataA dA0(10);
    DataA dA1(20);
    DataB dB0(100);
    DataB dB1(200);
    vector<DataA> datasA;
    datasA.push_back(dA0);
    datasA.push_back(dA1);
    vector<DataB> datasB;
    datasB.push_back(dB0);
    datasB.push_back(dB1);
    vector<IData*> datas;
    transform(begin(datasA), end(datasA), back_inserter(datas),
        [](DataA &a) -> IData* { return &a; } 
    );
    int resultA = calculateDataSum(datas);
    datas.clear();
    transform(begin(datasB), end(datasB), back_inserter(datas),
        [](DataB &b) -> IData* { return &b; } 
    );
    int resultB = calculateDataSum(datas);
    cout << resultA << endl;
    cout << resultB << endl;
    return 0;
}

或者,更简单地说:

int main()
{
    DataA dA0(10);
    DataA dA1(20);
    DataB dB0(100);
    DataB dB1(200);
    vector<IData*> datasA;
    datasA.push_back(&dA0);
    datasA.push_back(&dA1);
    vector<IData*> datasB;
    datasB.push_back(&dB0);
    datasB.push_back(&dB1);
    int resultA = calculateDataSum(datasA);
    int resultB = calculateDataSum(datasB);
    cout << resultA << endl;
    cout << resultB << endl;
    return 0;
}

或者,您可以完全摆脱vector

int calculateDataSum(initializer_list<IData*> datas)
{
    int sum = 0;
    for (auto d : datas)
    {
        sum += d->getNumber();
    }
    return sum;
}
int main()
{
    DataA dA0(10);
    DataA dA1(20);
    DataB dB0(100);
    DataB dB1(200);
    int resultA = calculateDataSum({&dA0, &dA1});
    int resultB = calculateDataSum({&dB0, &dB1});
    cout << resultA << endl;
    cout << resultB << endl;
    return 0;
}

甚至:

int calculateDataSum(const IData &arg)
{
    return arg.getNumber();
}
template <typename... Arguments>
int calculateDataSum(const IData &arg1, const Arguments&... args)
{
    return arg1.getNumber() + calculateDataSum(args...);
}
/* alternatively, in C++17 and later...
template <typename... Arguments>
int calculateDataSum(const IData &arg1, const Arguments&... args)
{
    int sum = arg1.getNumber();
    if constexpr(sizeof...(args) > 0)
    {
        sum += calculateDataSum(args...);
    }
    return sum;
}
*/
int main()
{
    DataA dA0(10);
    DataA dA1(20);
    DataB dB0(100);
    DataB dB1(200);
    int resultA = calculateDataSum(dA0, dA1);
    int resultB = calculateDataSum(dB0, dB1);
    cout << resultA << endl;
    cout << resultB << endl;
    return 0;
}

这是我解决问题的最终代码,谢谢大家

#include <iostream>
#include <vector>
using namespace std;
class IData
{
    public:
        virtual int getNumber() = 0;
};
class DataA : public IData
{
    public:
        DataA(int value) : _value(value) { }
        virtual int getNumber() override
        {
            return _value;
        }
    private:
        int _value = 0;
};
class DataB : public IData
{
    public:
        DataB(int value) : _value(value) { }
        virtual int getNumber() override
        {
            return _value;
        }
    private:
        int _value = 0;
};
class DataOther
{
    public:
        DataOther(int value) : _value(value) { }
        int getNumber()
        {
            return _value;
        }
    private:
        int _value = 0;
};
template<typename T>
int calculateDataSum(const vector<T> & datas)
{
    static_assert(std::is_base_of<IData, T>::value, "T does not inherit from IData");
    int sum = 0;
    for (int i = 0; i < datas.size(); i++)
    {
        sum += datas[i].getNumber();
    }
    return sum;
}
int main()
{
    DataA dA0(10);
    DataA dA1(20);
    DataB dB0(100);
    DataB dB1(200);
    DataOther dO0(500);
    vector<DataA> datasA;
    datasA.push_back(dA0);
    datasA.push_back(dA1);
    vector<DataB> datasB;
    datasB.push_back(dB0);
    datasB.push_back(dB1);
    vector<DataOther> datasO;
    datasO.push_back(dO0);
    int resultA = calculateDataSum(datasA);
    int resultB = calculateDataSum(datasB);

    //Error because DataOther does not inherit IData
    //int resultO = calculateDataSum(datasO); 
    cout << resultA << endl;
    cout << resultB << endl;
    return 0;
}

最新更新