假设我有一个名为BinaryClassifier
的策略界面,可以使用Sample
并返回double
,表示属于正类的Sample
对象的概率:
struct BinaryClassifier {
virtual ~BinaryClassifier(){}
virtual double classify(std::shared_ptr<Sample> sample) const = 0;
};
我们可能有几个BinaryClassifier
的实现,例如LogisticRegressionBinaryClassifier
。
Sample
又是一个只暴露两种方法的界面:
struct Sample {
virtual ~Sample() {}
InputFeatures const& get_input_features() const = 0;
double get_label() const = 0;
};
除了这两种方法之外,Sample
的具体实现暴露了完全不同的接口(即,它们是不相关的),它们共同的唯一方面是它们可以通过二元分类器进行分类。
到目前为止一切顺利。
当我们决定引入BinaryClassifier::train
方法时出现问题:
struct BinaryClassifier {
virtual ~BinaryClassifier(){}
virtual double classify(std::shared_ptr<Sample> sample) const = 0;
virtual void train(std::vector<std::shared_ptr<Sample>> samples) = 0;
};
此时,以下操作无效:
std::vector<std::shared_ptr<ConcreteSample>> concreteSamples = ...;
concreteBinaryClassifier.train(concreteSamples);
那是因为std::vector<std::shared_ptr<ConcreteSample>>
和std::vector<std::shared_ptr<Sample>>
是两种不相关的类型。
C ++ - ish解决方案将依赖于模板:
template<class SampleType>
virtual void train(std::vector<std::shared_ptr<SampleType>> samples) = 0; // non-working code, template method cannot be virtual
但模板方法不能是virtual
。尽管如此,我希望BinaryClassifier
成为一个战略界面,因为可能存在许多可能的BinaryClassifier
实现。在这一点上,即使设计看起来很合理,我也陷入了死胡同。
编辑:此外,对于BinaryClassifier
向量,可能会使用ConcreteSampleA
向量进行训练,同时对ConcreteSampleB
类型的对象进行分类< / p>
哪种方法是用大多数C ++建模这种情况的正确方法?
答案 0 :(得分:0)
您可以将BinaryClassifier设为模板类
template<SampleType> class BinaryClassifier
{
virtual void train(std::vector<std::shared_ptr<SampleType>> samples) = 0;
}
答案 1 :(得分:0)
您无法在BinaryClassifier
上训练ConcreteSampleA
,然后使用它对任意随机ConcreteSampleB
进行分类。因此,样本类型是BinaryClassifier
的固有部分。 Nullref的答案是合理的:使样本类型成为模板参数。
正如您所发现的,这意味着不再需要Sample
接口。好。 std::vector<int>
不要求int
也来自某个Element
接口。
当你摆脱东西时,InputFeatures
看起来也很可疑。我只是说get_input_features
必须返回一些std::tuple
,其成员类型都已定义std::less
。由于它不再是虚拟的,因此您不必关心不同的样本类型返回不同的元组。我绝对不会硬编码get_label
必须返回double
。无论如何,这是一种奇怪的标签类型。
现在你说用样本类型A进行训练然后对样本类型B进行分类可能是有意义的。这就是你进行改进的地方:似乎实际的兼容性要求是它们返回相同的元组。因此,Nullref的更好的解决方案是对BinaryClassifier
返回的元组类型的get_input_sample
进行模板化。
[编辑]
此外,classify
不需要共同拥有。通过Sample const&
。 train()
真的应该只使用迭代器对。 C ++约定是将一组对象作为范围传递。