我有一个名为UsbDevice的抽象类(主要是纯虚拟的)。它没有做太多,但三个派生类做:
class WindowsUsbDevice : public UsbDevice
class LinuxUsbDevice : public UsbDevice
class OsxUsbDevice : public UsbDevice
这些类中的每一个都没有真正添加任何公共方法 - 相反,它们只是UsbDevice抽象类的不同实现。
现在,我想创建一个派生自这些类中的任何一个的新类,我们称之为FancyUsbDevice。可以说它代表了一种特定的设备。
这个新类需要公开完整的UsbDevice接口(由中间类实现),以及暴露一些只使用UsbDevice接口上的方法的高级函数 - 不需要暴露任何特定于其中的一个那些中级班。
我可以看到三个可能的选项,我想知道它们是否可行,哪一个是最好的。
A)不继承,而是使FancyUsbDevice HAS-A UsbDevice *而不是IS-A。 (回避问题。我不喜欢这个选项,但感觉很安全。)
B)假设我有一个罕见的优势,即只有其中一个类实际构建在任何特定平台上,#ifdef继承字符串:(再次回避问题)
#ifdef WIN32
class FancyUsbDevice : public WindowsUsbDevice
#endif
#ifdef LINUX
class FancyUsbDevice : public LinuxUsbDevice
#endif
...
C) 模板!继承自模板类型:
Template<typename T> class FancyUsbDevice : public T
将其构造为子类型,并将其强制转换为接口:
FancyUsbDevice<WindowsUsbDevice> fancy_device;
FancyUsbDevice<UsbDevice> generic_fancy_device = dynamic_cast<FancyUsbDevice<UsbDevice>>(fancy_device);
然而,我认为这不会起作用,因为至少编译器会认为generic_fancy_device小于fancy_device,并且所有成员变量都会被偏移和破坏。 (我认为)
谢谢!抱歉,可以互换使用interface / abstract / pure虚拟。
答案 0 :(得分:2)
为什么不
#ifdef WIN32
typedef WindowsUsbDevice FancyUsbDevice;
#endif
#ifdef LINUX
typedef LinuxUsbDevice FancyUsbDevice;
#endif
或者如果你想用C ++ 11方式
#ifdef WIN32
using FancyUsbDevice = WindowsUsbDevice;
#endif
#ifdef LINUX
using FancyUsbDevice = LinuxUsbDevice;
#endif
无论如何,they are just the same。
答案 1 :(得分:1)
因此,如果我理解正确,您希望有一个类a)以与特定于操作系统的实现相同的方式实现UsbDevice
的接口,并且b)添加更多基于该接口的功能
最简单的事情就是不要创建另一个类,而只是将一个附加功能作为一组函数提供,并以UsbDevice
为参数。毕竟,您并没有真正添加 new 功能,您只是将现有功能组合到新功能中。如果您没有创建大量辅助函数,那么这可能是正确的。
如果必须单独成为一个类,请考虑将其作为UsbDevice
实现之上的装饰器。我想你有一些工厂方法,根据你所使用的操作系统为你提供正确的实现方法。装饰者看起来像这样:
class UsbMoreFuncDecorator: UsbDevice {
std::unique_ptr<UsbDevice> deviceImpl;
public:
UsbMoreFuncDecorator(Param param)
: deviceImpl(UsbDeviceFactory.create(param))
// ^-- Win or OsX or Linux - doesn't matter
{}
// delegate the UsbDevice virtual functions to the actual implementation
virtual void someBasicUsbDeviceFunc() final {
deviceImpl->someBasicUsbDeviceFunc();
}
// use the UsbDevice functions to compose more functionality
void someMoreFunctionality() {
someBasicUsbDeviceFunc();
someOtherUsbDeviceFunc();
}
};
答案 2 :(得分:0)
选项B可以完全按照您的要求进行操作。而不是在这一点上使用ifdef,在其他地方说它可能更干净:
#ifdef WIN32
typedef WindowsUsbDevice NativeUsbDevice
// any other such typedefs needed for Windows
#endif // and similarly for Linux and OSX
然后
class FancyUsbDevice : public NativeUsbDevice
如果您使用的是C ++ 11,则可以使用“using”而不是“typedef”。