如果我想使类适应,并且可以从外部选择不同的算法 - C++中最好的实现是什么?
我主要看到两种可能性:
使用抽象基类并传递具体对象
使用模板
这是一个小例子,在各种版本中实现:
版本1:抽象基类
class Brake { public: virtual void stopCar() = 0; }; class BrakeWithABS : public Brake { public: void stopCar() { ... } }; class Car { Brake* _brake; public: Car(Brake* brake) : _brake(brake) { brake->stopCar(); } };
版本2a:模板
templateclass Car { Brake brake; public: Car(){ brake.stopCar(); } };
版本2b:模板和私有继承
templateclass Car : private Brake { using Brake::stopCar; public: Car(){ stopCar(); } };
来自Java,我自然倾向于始终使用版本1,但模板版本似乎经常是首选,例如在STL代码中?如果这是真的,是因为内存效率等(没有继承,没有虚函数调用)?
我意识到版本2a和2b之间没有太大的区别,请参阅C++ FAQ.
你能评论一下这些可能吗?
这取决于你的目标.如果您可以使用版本1
打算更换汽车刹车(在运行时)
打算将Car传递给非模板函数
我通常更喜欢使用运行时多态性的版本1,因为它仍然是灵活的,并允许您使Car仍具有相同的类型:Car
是另一种类型Car
.如果你经常使用制动器时你的目标很棒,我建议你使用模板化的方法.顺便说一句,这称为基于策略的设计.你提供制动政策.例子,因为你说你用Java编程,可能你还不熟悉C++.一种方法:
templateclass Car { Accelerator accelerator; Brakes brakes; public: void brake() { brakes.brake(); } }
如果您有很多策略,可以将它们组合到自己的结构中,然后传递它,例如作为SpeedConfiguration
收集Accelerator
,Brakes
还有更多.在我的项目中,我尝试保留大量无代码模板,允许将它们编译成自己的目标文件,而不需要在头文件中使用代码,但仍然允许多态(通过虚函数).例如,您可能希望保留非模板代码可能在基类中多次调用的常见数据和函数:
class VehicleBase { protected: std::string model; std::string manufacturer; // ... public: ~VehicleBase() { } virtual bool checkHealth() = 0; }; templateclass Car : public VehicleBase { Accelerator accelerator; Breaks breaks; // ... virtual bool checkHealth() { ... } };
顺便说一下,这也是C++流使用的方法:std::ios_base
包含不依赖于char类型的标志和东西,或者像openmode,format flags和stuff这样的特性,std::basic_ios
然后是继承它的类模板.这还通过共享类模板的所有实例化所共有的代码来减少代码膨胀.
一般应避免私人继承.它在很少有用,在大多数情况下,遏制是一个更好的主意.通常情况下,当size非常重要时,情况正好相反(例如,基于策略的字符串类):从空策略类(仅包含函数)派生时,可以应用空基类优化.
阅读Herb Sutter 对继承的使用和滥用.
经验法则是:
1)如果在编译时选择具体类型,则更喜欢模板.它会更安全(编译时错误与运行时错误)并且可能更好地优化.2)如果选择是在运行时进行的(即由于用户的操作),则实际上没有选择 - 使用继承和虚函数.
其他选择:
使用访客模式(让外部代码适用于您的班级).
外化类的某些部分,例如通过迭代器,基于通用迭代器的代码可以对它们起作用.如果您的对象是其他对象的容器,则此方法效果最佳.
另请参阅策略模式(里面有c ++示例)
模板是一种让类使用您并不真正关心类型的变量的方法.继承是一种基于其属性定义类的方法.它是"is-a"与"has-a"的问题.