我在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;
}
答案 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;
}
使用这种方法,您还可以混合使用,因此可以在其中包含DataA
和DataB
的向量。
答案 1 :(得分:1)
从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
的孩子。
答案 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;
}