C++ 在本例中,如何避免代码重复?
我有一个简单的库(我们称之为C++ 在本例中,如何避免代码重复?,c++,C++,我有一个简单的库(我们称之为库#1),它可以处理一些数据向量(例如时间序列)。我想创建一个新的库(library#2),它基本上具有大多数(但不是全部)相同的函数,但只作用于该向量中的单个数据点。我设想一个解决方案,它是现有库的一个薄包装,可以最大限度地减少代码重复 下面是简单的库#1: class Foo { private: std::vector<double> data; public: // Some constructors double get_
库#1
),它可以处理一些数据向量(例如时间序列)。我想创建一个新的库(library#2
),它基本上具有大多数(但不是全部)相同的函数,但只作用于该向量中的单个数据点。我设想一个解决方案,它是现有库的一个薄包装,可以最大限度地减少代码重复
下面是简单的库#1
:
class Foo {
private:
std::vector<double> data;
public:
// Some constructors
double get_data_at_timepoint(int timepoint) const;
// Some other methods
}
其中(重要)执行某些操作
调用在某个时间点获取数据
:
void Bar::do_something() {
// ...
double x = foos[some_idx].get_data_at_timepoint(some_timepoint);
// ...
};
我想要的Library#2
也是Library#1
在单个时间点上。比如:
class Foo2 {
private:
double data;
public:
double get_data() const;
// All those other methods of Foo
}
class Bar2 {
private:
std::vector<Foo2> foos;
public:
Foo2 get_this_foo_2(int idx) const;
void do_something();
// All those other methods of Bar
}
显然,Foo2
基本上只是Foo
,但只有一个数据条目。我可以重写所有的Foo
,但是我必须复制所有的方法。相反,我想定义长度为1(单个数据点)的Foo
薄包装
对于Foo2
,有两个选项:(1)子类Foo
,或(2)让Foo2
成为Foo
的唯一ptr的包装器。我认为(2)更好,因为用户不应该访问基类Foo
中的时间点
我还希望避免为Bar
编写额外的代码。当然,dou_something
的功能需要在Bar2
中稍加调整,但总的来说,这两个功能似乎是平行的。Bar
中的许多其他方法也是相同的
如何避免Foo2
和Bar2
的代码重复
template <typename FooType>
class BarBase {
private:
std::vector<FooType> foos;
protected:
virtual double get_data_from_foo(unsigned int, void*) = 0;
public:
void do_something();
// all other methods that used to be in Bar
};
class Bar : public BarBase<Foo> {
protected:
virtual void get_data_from_foo(unsigned int id, void* time_ptr) {
return foos[id].get_data_at_timepoint(*(timepoint_t*)time_ptr);
}
};
class Bar2 : public BarBase<Foo2> {
protected:
virtual void get_data_from_foo(unsigned int id, void* dummy) {
return foos[id].get_data();
}
};
模板
巴巴多斯类{
私人:
std::矢量foos;
受保护的:
虚拟双精度从\u foo获取\u数据(无符号整数,void*)=0;
公众:
虚空做某事;
//以前在酒吧使用的所有其他方法
};
类酒吧:巴巴多斯公共酒吧{
受保护的:
虚拟无效从\u foo获取\u数据\u(未签名的整数id,无效*时间\u ptr){
返回foos[id]。在时间点(*(时间点t*)时间点ptr)获取数据;
}
};
第2类:公共巴巴多斯{
受保护的:
虚拟void从\u foo获取\u数据(无符号int-id,void*dummy){
返回foos[id]。获取_数据();
}
};
您必须在BarBase::do\u something()中调用get\u data\u from\u foo()。您还必须计算时间点并将其传递给该函数,而不管是否需要它
或者,如果您不介意do_something()中的代码重复,请从_foo()中删除get_data_,并向Bar和Bar2中的每一个添加一个do_something()成员函数,分别定义它们这就是为什么在许多C++库中,类本身只有少量的成员函数,它们只限于描述该类型所需的内容。其他所有问题都是使用免费函数解决的,这使您能够以更好的方式模块化代码和重用功能 因此,只使用成员函数来隐藏类的数据结构的实现细节,或者如果需要虚拟函数,那么对于大多数情况下希望使用自由函数的所有其他内容 实现可能是这样的(这只是一个概念验证代码,用于说明自由函数的用法):
从
Bar
继承并隐藏do\u something
,使用一个新的方法执行您想要的操作。但是get\u这个\u foo\u 2
实际上会返回一个foo
对象,而不是Foo2
,对吗?您可以使用Bar中当前的所有方法创建一个BarBase模板类,但是添加一个抽象的get_data_from_foo成员函数。使Bar从BarBase继承,Bar2从BarBase继承。你必须做的每一件事都是使用相应的方法实现GETXDATAYFROXFOO。这就是为什么在许多C++库中,类本身只有少量的成员函数,它们只限于描述这个类型所需要的。其他所有问题都是使用免费函数解决的,这使您能够以更好的方式模块化代码和重用功能。因此,只使用成员函数来隐藏类的数据结构的实现细节,或者如果需要虚拟函数,那么对于大多数情况下希望使用免费函数的所有其他内容,都可以使用。这太棒了,c++
太棒了,太棒了。谢谢
void Bar2::do_something() {
// ...
double x = foos[some_idx].get_data();
// ...
};
template <typename FooType>
class BarBase {
private:
std::vector<FooType> foos;
protected:
virtual double get_data_from_foo(unsigned int, void*) = 0;
public:
void do_something();
// all other methods that used to be in Bar
};
class Bar : public BarBase<Foo> {
protected:
virtual void get_data_from_foo(unsigned int id, void* time_ptr) {
return foos[id].get_data_at_timepoint(*(timepoint_t*)time_ptr);
}
};
class Bar2 : public BarBase<Foo2> {
protected:
virtual void get_data_from_foo(unsigned int id, void* dummy) {
return foos[id].get_data();
}
};
#include <iostream>
#include <vector>
class Foo {
private:
std::vector<double> data = {1,2,3};
public:
std::vector<double>::const_iterator begin() const {
return data.begin();
}
std::vector<double>::const_iterator end() const {
return data.end();
}
double first() const {
return *begin();
}
};
class Foo2 {
private:
double data = 42;
public:
const double * begin() const {
return &data;
}
const double * end() const {
return &data + 1;
}
double first() const {
return *begin();
}
};
template<typename T>
double get_data_at_timepoint(const T &obj, size_t index) {
auto it = obj.begin()+index;
return *it;
}
template<typename T>
double get_data(const T &obj) {
return obj.first();
}
int main()
{
Foo f;
Foo2 f2;
double d = get_data_at_timepoint(f, 2);
double d2 = get_data_at_timepoint(f2, 0);
double d3 = get_data(f);
double d4 = get_data(f2);
// double d2 = get_data_at_timepoint(f2, 0);
std::cout << "get_data_at_timepoint " << d << " " << d2 << std::endl;
std::cout << "get_data " << d3 << " " << d4 << std::endl;
}
template<>
double get_data_at_timepoint<Foo>(const Foo &obj, size_t index) {
// Foo related implementation
}