我需要类来实现类似的东西(不同类型的神经网络),但有一些不同的接口。
做研究,我想在写作课上用不同的神经网络运行程序。我希望能够替换和现有的类型。通过运行时启动参数来处理这个问题会很好,但编译时放置也可以。
我看到了至少5种方法的缺点,这些缺点使我无法使用它们:
- 用虚函数实现基类,并将指向基类的指针置于组合类中。主要缺点:对象切片的风险,克隆函数的地狱,派生类的赋值和比较操作符,dynamic_cast或类似的肮脏技巧来识别应用类型特定函数的实际对象类型。
- 使用模板的神经网络类型。缺点:这将需要将大部分代码移动到模板中,因此我将不得不将大量实现代码放入头文件。
- 通过添加占位符函数统一接口。缺点:接口会变成肮脏的地狱。
- 使用c++预处理器#ifdef块来分隔两个版本的代码。缺点:它是肮脏的复制/粘贴代码块和超过2个类的地狱。
- 使用适配器模式,提供统一的接口并隐藏细节。缺点:实际上,它将与指针实现,因此将遭受(1)和(2),但(2)将只在适配器接口。
在现代c++中有没有更好的方法来实现这个?有些东西告诉我,我可以围绕用std::function构造的块构建某种解决方案,但我还不确定。
好了,我找到了解决办法,真不知道为什么我昨天犯了错误,把事情弄得太复杂了。
该解决方案适用于编译时。对于运行时,我将使用原始问题中的选项(1)。
总体思想是使用带有特定类参数的重载函数,这将允许编译时多态性选择正确的函数,该函数将采用正确的类型进行设置,调优等。
<<p>解决方案/strong>class NNType1 { … };
class NNType2 { … };
using NeuralNetwork = NNType1;
// using NeuralNetwork = NNType2;
class Creature {
NeuralNetwork nn;
public:
template <typename T> void setupNN(NNType1&);
template <typename T> void tuneNN(NNType1&);
};
template<> Creature::setupNN(NNType1& nn) {
…
}
实际上,使用模板代替重载函数,是为了简化类声明,避免所有类型的重载函数列表。
现在所有使用自定义部分接口的代码都放入这些setupNN/tuneNN函数中,这些函数特定于具体的类NNType1/NNType2/等。对于Creature的泛型代码,这些函数隐藏了实现细节。
利润
- 易于实现
- 现在代码被分割成小函数,没有if/switch
- 不使用RTTI信息,不使用dynamic_cast等
有任何意见,更正,改进建议吗?