C ++将vector <data>转换为vector <idata>

时间:2019-01-29 17:09:40

标签: c++ interface containers

我在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;
}

4 个答案:

答案 0 :(得分:2)

最明显的方法是使用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的向量。

答案 1 :(得分:1)

从C ++类型系统的角度来看,vector<Data>vector<IData>是完全不同的类型,而与DataIData的层次关系无关。

您的问题的一种解决方案是基于模板的即席多态性:

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的孩子。

答案 2 :(得分: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;
}

答案 3 :(得分:0)

vector<DataA>vector<DataB>元素复制到vector<IData>中将不起作用,因为它会受到object slicing的影响。您需要使用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;
}