Home > database >  Trigger added methods of derived class by method in base class
Trigger added methods of derived class by method in base class

Time:09-18

I want to implement a simple test structure. Here is how I created base class and derived class.

testBase.h:

class TestBase {
public:
    TestBase() {}
    virtual void TestStart() = 0;
    virtual void TestEnd() = 0;
    void RunTest() {  
        // I need code here to trigger a chain of calls
    }
};

classifierTest.h:

#include "testBase.h"

class ClassifierTest: public TestBase
{
public:
    ClassifierTest() {
    
    }
    void TestStart();
    void TestEnd();

    void Test1();
    void Test2();
    void Test3();
};

classifierTest.cpp:

#include "classifierTest.h"

void ClassifierTest::TestStart() {

}

void ClassifierTest::TestEnd() {

}

void ClassifierTest::Test1(){

}

void ClassifierTest::Test2(){

}

void ClassifierTest::Test3(){

}

main function:

ClassifierTest *classifierTest = new ClassifierTest();
classifierTest->RunTest();

Suppose Test1(), Test2() and Test3() are my test methods, and I may add more tests here in future. My goal is that when I call RunTest() in the main function, then these test methods are called one by one, after TestStart(), and before TestEnd().

so they would run like:

  • TestStart()
  • Test1()
  • TestEnd()
  • TestStart()
  • Test2()
  • TestEnd()
  • TestStart()
  • Test3()
  • TestEnd()

I don't want to specifically add test method in the base class. But the question is how to trigger these chain of calls from RunTest(). So the base trigger methods that it doesn't know about them.

I believe it should be sth like reflection in .net?

CodePudding user response:

You are basically asking for reflection which isnt present in C (yet). Now the quesiton is what comprosmise you are willing to make.

If you are fine with writing some code to manually register the test functions, then they don't need to be members and a possible solution is this:

#include <functional>
#include <vector>
#include <iostream>
class TestBase {
public:
    TestBase() {}
    virtual void TestStart() = 0;
    virtual void TestEnd() = 0;
    
    void RunTest() {  
        for (const auto& test_fun : test_functions){
            TestStart();
            test_fun();
            TestEnd();
        }
    }
    using test_function = std::function<void()>;
    void register_test(const test_function& fun){ test_functions.push_back(fun); }
private:
    
    std::vector<test_function> test_functions;
};

class ClassifierTest: public TestBase
{
public:
    ClassifierTest() {
        register_test([](){ std::cout << "test 1\n";});
        register_test([](){ std::cout << "test 2\n";});
    }
    void TestStart() { std::cout << "test start\n";}
    void TestEnd() { std::cout << "test end\n";}
};

int main() {
    ClassifierTest{}.RunTest();
}

Output:

test start
test 1
test end
test start
test 2
test end

Note that if you capture this the lambdas can use members, so there isnt much difference to your initial approach and the amount of code to write is also comparable:

class ClassifierTest2: public TestBase
{
public:
    ClassifierTest2() {
        register_test([this](){ std::cout << "test 1, x = " << x << "\n";});
        register_test([this](){ std::cout << "test 2, x = " << x << "\n";});
    }
    void TestStart() {   x;std::cout << "test start\n";}
    void TestEnd() { std::cout << "test end\n";}
private:
    int x = 0;
};

int main() {
    ClassifierTest2{}.RunTest();
}

Output:

test start
test 1, x = 1
test end
test start
test 2, x = 2
test end

As mentioned already in a comment, if you manually register TestStart and TestEnd as well, then there is no need for the derived classes. It could be just a class Test with register_test_start(std::function<void()>) and register_test_end(std::function<void()>) or pass them as parameters to the constructor.

  • Related