我有一段代码,它将大量计算应用于一组数据。此数据按类进行组织,主要由标量以及浮点数和双精度数组组成。问题是类上的变量取决于输入文件结构,即文件 A 可能有 10 个标量变量,B 可能有 20 个数组。如何创建抽象来处理这些异构数据?
我想创建一个类 Data,并为继承自 Data 的每个不同输入 A 和 B 创建一个特定的类。但是我有一个大问题:
在代码中,我只想将数据集作为 Data 类,在
vector<Data> datas;
Data d = new Data();
datas.push_back(d);
我不想做
vector<Data> datas;
Data d = new A();
datas.push_back(d);
但这意味着父类将访问变量、构造函数等的子类,如果可能的话,我现在不这样做(请注意,应用程序只读取文件 A 或 B,而不是在同一执行中同时读取两者,我没有问题在编译时设置哪个,只将类 A 或 B 添加到代码中)
PS:在由非计算机科学家编写的原始代码中,他们将创建 Data 类和声明中的 #include"variables.cxx"。它显然有效,但应不惜一切代价避免......
你需要一个指向基类的指针数组。这允许 vector 使用一种固定大小的类型(指向基类的指针),但该类型表示不同大小的所有对象。
std::vector<base*> datas;
datas.push_back(new derived);
如果你有 c++11,那么 vector 可以为你管理内存:
std::vector<std::unique_ptr<base>> datas;
datas.push_back(std::make_unique<derived>());
在C++中使用动态绑定,它允许您通过父类型的指针访问子类中的函数(构造函数除外)。这是一个示例:
class Data
{
public:
virtual void func() = 0;
};
class A : public Data
{
public:
void func();
};
class B : public Data
{
void func();
};
然后,您可以像这样处理数据:
vector<Data*> datas;
Data *d = new A();
d->func();//do something, for example read data from files
datas.push_back(d);
模板
正如您所说,您很乐意在编译时选择类型,一种选择是在数据类型上模板化代码:
template<typename Data>
void doComputations() {
std::vector<Data> datas;
Data d;
datas.push_back(d);
}
doComputations<A>();
那么你不需要基Data
类,只需要一个由A
和B
共享的隐式接口。但这可能意味着你的很多代码必须被模板化,而这些代码可能不是你想要的。
多态性
使用堆栈分配的对象
如果要利用Data
基类的运行时多态行为,则需要存储指针向量。
填充向量的一种方法是拥有A
和B
的单独向量,然后是一个包含Data
原始指针的向量来执行计算:
std::vector<A> a_datas;
std::vector<B> b_datas;
a_datas.push_back(A{});
a_datas.push_back(A{});
b_datas.push_back(B{});
std::vector<Data*> datas;
for (auto& a : a_datas)
datas.push_back(&a);
for (auto& b : b_datas)
datas.push_back(&b);
doComputations(datas);
使用堆分配的对象
或者更灵活的方法是在堆上分配对象并使用一个智能指针向量管理它们:
struct Data {
public:
virtual ~Data(){}
//...
};
struct A : Data { /* ... */ };
struct B : Data { /* ... */ };
std::unique_ptr<Data> loadData() {
if ( condition )
return std::make_unique<A>();
else
return std::make_unique<B>();
}
}
std::vector<std::unique_ptr<Data>> datas;
datas.push_back(loadData());
datas.push_back(loadData());
doComputations(datas);