允许模拟类从最终类继承

Aja*_*jay 1 c++ unit-testing c++11 c++14

我们可以使用新的 C++ 关键字 声明一个最终/密封的不可继承类final。

class Generator final
{

};
Run Code Online (Sandbox Code Playgroud)

这个类可能继承自其他类,可能有也可能没有虚拟(继承与否)。但是,如何制作它final,同时允许一个类继承它呢?

我们主要需要从真实类派生出一个模拟类(有或没有后期绑定,因此virtual并不重要)。如何使它工作:

class MockGenerator : Generator{};
Run Code Online (Sandbox Code Playgroud)

但是不允许任何其他继承?

ste*_*anv 5

一种可能性:使用 Final 的定义,并在生成测试环境时将其定义为空。

#ifdef MOCK
#define CLASS_FINAL
#else
#define CLASS_FINAL final
#endif
Run Code Online (Sandbox Code Playgroud)

编辑:我同意 utnapistim 的评论:这不是建议,只是技术可能性(但至少比#define final)。

  • 请不要推荐这个。它是一种测试与生产代码不同的代码的解决方案(并且根据定义,不是您最终交付的代码)。如果编写的代码不可测试,那就是一个设计问题,应该在设计级别解决,而不是在“破解关键字的含义”级别解决(我在 SO 上看到了类似的解决方案,提出“#define private public”作为解决方法无法测试的代码)。 (7认同)

utn*_*tim 5

但是,如何使它成为最终的,同时允许一个类继承它呢?

那是不可能的。

我们主要需要从真实类派生出一个模拟类(有或没有后期绑定,因此虚拟并不重要)。

如果类是最终的,则不需要从它派生。如果您确实需要从中派生,则它不是 final。选一个。

编辑:您可以为您的课程添加限制,但这些限制是界面的代价:

class Generator // not final
{
    Generator(); // the only accessible constructor is private

    // whitelist who has access to this constructor
    friend class MockGenerator;
public:
    // no public constructors here except for copy & move

    Generator(Generator&);
    Generator(Generator&&);
    ...

    // provide controlled access to the private constructor
    static Generator make_generator() { return Generator(); }

    // rest of API here
};
Run Code Online (Sandbox Code Playgroud)

这是一个允许它的工厂和 MockGenerator 特化调用它的构造函数的类。但是,这是以阻止琐碎的构造为代价的。

旧代码(不再可编译):

Generator instance;
Run Code Online (Sandbox Code Playgroud)

新代码(由私有构造函数强制执行):

auto instance = Generator::make_generator();
Run Code Online (Sandbox Code Playgroud)