C++ 抽象基类w/o多态性

C++ 抽象基类w/o多态性,c++,inheritance,interface,polymorphism,C++,Inheritance,Interface,Polymorphism,为什么会有一个抽象基类为一个只有一个(始终和永远)接口的库定义接口派生类?您可能希望将实现换成单元测试之类的东西您可能希望将实现换成单元测试之类的东西这样做的一个原因是为了可测试性。当依赖对象的依赖项被定义为接口时,测试依赖对象要简单得多。这使模拟或存根变得容易。这样做的一个原因是为了可测试性。当依赖对象的依赖项被定义为接口时,测试依赖对象要简单得多。这提供了模拟或存根的简单功能。如果您可以100%确定始终只有一个派生类?没什么理由。但是:在现实中,您很难对任何事情都百分之百确定,当然也不能确定

为什么会有一个抽象基类为一个只有一个(始终和永远)接口的库定义接口派生类?

您可能希望将实现换成单元测试之类的东西

您可能希望将实现换成单元测试之类的东西

这样做的一个原因是为了可测试性。当依赖对象的依赖项被定义为接口时,测试依赖对象要简单得多。这使模拟或存根变得容易。

这样做的一个原因是为了可测试性。当依赖对象的依赖项被定义为接口时,测试依赖对象要简单得多。这提供了模拟或存根的简单功能。

如果您可以100%确定始终只有一个派生类?没什么理由。但是:在现实中,您很难对任何事情都百分之百确定,当然也不能确定代码的未来

如果您可以100%确定始终只有一个且恰好只有一个派生类?没什么理由。但是:在现实中,您很难对任何事情都百分之百确定,当然也不能确定代码的未来

违反规则

简而言之,不要这样做

那些说“为了测试”的人忽略了你可以替换的东西

Base < - > Derived
Base < - > DerivedForMockingAndTesting
Base<->派生
底座<->衍生的锁紧和测试

Derived<->derivedFormocking和testing
也就是说,让您现有的实现
派生的
作为“抽象”在单元测试中模拟和测试。

违反了

简而言之,不要这样做

那些说“为了测试”的人忽略了你可以替换的东西

Base < - > Derived
Base < - > DerivedForMockingAndTesting
Base<->派生
底座<->衍生的锁紧和测试

Derived<->derivedFormocking和testing

也就是说,让您现有的实现
派生的
作为“抽象”在单元测试中模拟和测试。

您可能会发现该类的不同版本需要二进制兼容。您还可能会发现,出于其他原因,您希望封装类的定义-例如,因为定义需要一个包含糟糕宏的头,诸如此类的东西,或者包含定义类所需内容的头有很长的编译时间


例如,我编写了一个类来封装我的操作系统提供的功能——现在,动态加载和创建窗口之类的功能。尽管对于一个编译目标(Windows等)只有一个实现,但我选择使用运行时抽象,因为我想保证我的其余代码从未看到特定于平台的头,并且Windows头中充满了大量宏和其他内容,我不希望它们泄露出去。

您可能会发现该类的不同版本需要二进制兼容。您还可能会发现,出于其他原因,您希望封装类的定义-例如,因为定义需要一个包含糟糕宏的头,诸如此类的东西,或者包含定义类所需内容的头有很长的编译时间


例如,我编写了一个类来封装我的操作系统提供的功能——现在,动态加载和创建窗口之类的功能。尽管对于一个编译目标(Windows等)只有一个实现,但我选择使用运行时抽象,因为我想保证我的其余代码从未看到特定于平台的头,并且Windows头中充满了大量宏和其他内容,我不想让它们泄露出去。

最明显的原因是能够将类的 实现在源文件中,而不是在头文件中。就这些 标头中公开的是抽象基类(和工厂函数) 必须构造它,但这可能是静态成员)。这 避免包含任何成员数据的头文件;皮姆普尔 习语在C++中更为习惯,但使用抽象类
这远非未知,而且效果相当好。

最明显的原因是能够将类的 实现在源文件中,而不是在头文件中。就这些 标头中公开的是抽象基类(和工厂函数) 必须构造它,但这可能是静态成员)。这 避免包含任何成员数据的头文件;皮姆普尔 习语在C++中更为习惯,但使用抽象类
这还远远不知道,而且效果也不错。

过去,除非你考虑IOC和依赖注入,否则我想不出一个好的理由。这个类是否有可能在以后更改它的实现,而不更改签名?也许这只是我的问题,但是扩展类本身并添加一些方法(或构造函数)来为测试设置私有变量不是更容易(也不容易出错)吗?或者,如果我想添加日志记录,我可以同样轻松地覆盖这些方法,处理日志记录并调用超级类。否则,您必须实现两次通用功能,这在我看来是个坏主意。我通常在.NET中工作,所以我更喜欢在模拟中设置期望值,然后重播行为。在C++中,这可能完全不同。不必编写无意义的接口来完成这一任务。您也可以模拟具体类(只要它们没有被密封,并且您想要模拟的方法是
virtual
)(在c#中,将所有方法都虚拟化并不是特别好的编码风格,您甚至可能无法控制类)。但是,即使您想要替换类的完整实现,您也不需要像Jason所说的那样使用接口