C ++ вектор <Data>к вектору <IData> - PullRequest
0 голосов
/ 29 января 2019

У меня есть проблема в 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 голосов
/ 29 января 2019

Копирование элементов 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;
}

Или вы можете просто избавиться от *Всего 1015 * с:

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;
}
0 голосов
/ 29 января 2019

Наиболее очевидный подход, поскольку у вас уже есть базовый класс с виртуальными методами, - это использование 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;
}

. При таком подходе вы также можете смешивать, чтобы вы могли иметь вектор с обоимиDataA и DataB в нем.

0 голосов
/ 29 января 2019

Это мой окончательный код для решения моей проблемы, спасибо всем

#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;
}
0 голосов
/ 29 января 2019

С точки зрения системы типов C ++ vector<Data> и vector<IData> - это совершенно разные типы независимо от иерархических отношений Data и 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...