Reputation: 21510
I saw this code online and I was wondering how it is implemented. Since member function pointers cannot be assigned to a base class's member function pointers I am curious where the pointers for the derived class's member functions are being stored and how.
This is the header file with the test declarations
#ifndef TestStudent_h
#define TestStudent_h
#include <iostream>
#include <string>
// Note 1
#include "TestCase.h"
#include "TestSuite.h"
#include "TestCaller.h"
#include "TestRunner.h"
#include "Student.h"
class StudentTestCase : public TestCase { // Note 2
public:
// constructor - Note 3
StudentTestCase(std::string name) : TestCase(name) {}
// method to test the constructor
void testConstructor();
// method to test the assigning and retrieval of grades
void testAssignAndRetrieveGrades();
// method to create a suite of tests
static Test *suite ();
};
#endif
And this is the implementation of the function that adds the member functions to some sort of list
// method to create a suite of tests - Note 7
Test *StudentTestCase::suite () {
TestSuite *testSuite = new TestSuite ("StudentTestCase");
// add the tests
testSuite->addTest (new TestCaller
("testConstructor", &StudentTestCase::testConstructor));
testSuite->addTest (new TestCaller
("testAssignAndRetrieveGrades",
&StudentTestCase::testAssignAndRetrieveGrades));
return testSuite;
}
I was wondering what data type the member functions are being stored in since they cannot be stored in any function pointer type known to the base class.. Also the location where they are stored will have to know the type of the class under which these are defined since whatever entity that calls these objects will need to "link" these functions with objects of that type too right? Specifically in this function how will TestCaller
know how to call the member functions that were added to it?
Upvotes: 1
Views: 65
Reputation: 76297
My guess is that TestCaller
has a constructor that looks like
template<class Callee>
TestCaller(
const std::string &description,
void (Callee::*test_method)());
Note that:
Within the body of this constructor (i.e., when it is instantiated), the type of Callee
is known.
TestCaller
itself must store test_method
in a way that does not "know" Callee
, since it is not itself a template class parameterized by Callee
(and in fact, there might be more than a single Callee
).
So this is a classic case for type erasure. There are many libraries that do this (e.g., boost::TypeErasure
or boost::any
).
The idea is that TestCaller
stores (probably indirectly) pointers to a non-template base class. There are templated versions of a derived class. Within this templated ctor, the derived class is instantiated, and an object of this type is dynamically allocated. What is stored, though is a pointer to the non-template base class.
Upvotes: 4