自动注册新的派生类/创建者方法

Automatically register new derived class / creator method

本文关键字:创建者 方法 派生 注册      更新时间:2023-10-16

我想如果我给出一个我想要达到的目标的例子会更容易。

假设我想实现一个单元测试环境,在其中实现一个新的单元测试将涉及从给定的基类派生,并且(可能)遵循涉及放置额外宏的指导方针。这样的新测试将自动添加到测试列表中,在某个点上一个接一个地运行。但是有两件事:

  1. 我试图使创建每个新测试尽可能快速和容易,特别是当涉及到修改文件以外的文件与测试本身。一个完美的情况是,实现一个新测试不需要触及项目中的任何其他文件。这可以通过单例和可能的CRTP来实现,但是现在来看看第2点,

  2. 目标是具有有限RAM数量的MCU (ROM一般不是问题),我希望能够直接在目标平台上运行测试。因此,在整个应用程序生命周期中占用内存的静态对象是不可接受的。相反,我希望能够仅在需要运行时单独创建和删除每个测试。

基本上,问题归结为一种自动将派生类型(或创建者方法)注册到具有最小RAM开销(我假设会有一些,即至少指向上述方法的指针)的工厂的方法。

很抱歉没有代码示例,但如果没有提交一个给定的实现,这里真的没有什么可展示的。

你能创建一个函数指针的静态/全局向量吗?这些将是指向每个测试类的创建者/工厂函数的指针。工厂函数返回指向基测试类的指针。我本想把它写出来,但我认为代码更容易写和理解。

class TestBase
{
  public:
    static char registerTest(<function ptr type> creator) {
      testCreators.push_back(creator);
      return 1;
   }
    static void runTests()
    {
      for (auto creator : testCreators)
      {
        auto newTestClass = creator();
        newTestClass->tests();
        delete newTestClass;
      }
    }
  private:
    void tests() = 0;
    std::vector<function ptr type> testCreators;
};

然后是派生类

class SpecificTest : public TestBase
{
  // Pretend test code is here.
  private:
  static char dummy;
};
// Plan old C function. Need to establish naming conventions so as
// not to get multiple symbol errors during linking. Kind of fragile.
TestBase* specificTestCreator()
{
  return new SpecificTest();
}

在。cpp文件中为SpecificTest

char SpecificTest::dummy = TestBase::registerTest(specificTestCreator);

我试过编译或运行这个,但我认为它基本上是合理的。

我根据Michael提供的答案创建了一个示例,编译并运行了它。邮编如下

TestBase.h:

#ifndef TESTBASE_H_
#define TESTBASE_H_
#include <vector>
class TestBase {
public:
    TestBase();
    virtual ~TestBase();
    static void RunAllTests();
protected:
    virtual void test() = 0;
    static char addTestCreator(TestBase* (*creator)());
private:
    static std::vector<TestBase* (*)()> &getTests();
};
#endif /* TESTBASE_H_ */

TestBase.cpp

#include "TestBase.h"
TestBase::TestBase() {
}
TestBase::~TestBase() {
}
char TestBase::addTestCreator(TestBase* (*creator)())
{
    getTests().push_back(creator);
    return 0;
}
void TestBase::RunAllTests()
{
    for(std::vector<TestBase* (*)()>::iterator it = getTests().begin(); it != getTests().end(); it++)
    {
        TestBase *t = (*it)();
        t->test();
        delete t;
    }
}
std::vector<TestBase* (*)()> &TestBase::getTests()
{
    static std::vector<TestBase* (*)()> v;
    return v;
}

ConcreteTest1.h:

#ifndef CONCRETETEST1_H_
#define CONCRETETEST1_H_
#include "TestBase.h"
class ConcreteTest1: public TestBase {
public:
    ConcreteTest1();
    virtual ~ConcreteTest1();
protected:
    void test();
private:
    // both here can be expanded with a macro to make it
    // easier as they'll be same for all derived classes
    static char dummy;
    static TestBase *creator();
};
#endif /* CONCRETETEST1_H_ */

ConcreteTest1.cpp:

#include "ConcreteTest1.h"
#include <iostream>
// can be expanded with a macro
char ConcreteTest1::dummy = TestBase::addTestCreator(ConcreteTest1::creator);
// can be expanded with a macro
TestBase* ConcreteTest1::creator()
{
    return new ConcreteTest1();
}
ConcreteTest1::ConcreteTest1()
{
    std::cout << "Creating test 1" << std::endl;
}
ConcreteTest1::~ConcreteTest1()
{
    std::cout << "Deleting test 1" << std::endl;
}
void ConcreteTest1::test()
{
    std::cout << "Running test 1" << std::endl;
}

同样ConcreteTest2.cpp/. h .

从main调用:

TestBase::RunAllTests();

输出是:

Creating test 1
Running test 1
Deleting test 1
Creating test 2
Running test 2
Deleting test 2

这正是我想要达到的。