Note: The following is an abstraction of the problem I'm trying to tackle.
Context: I'm trying to figure out a POC of the general logic for the following rather tricky situation: An abstract base class A has a number of derivative classes B_1,...,B_n which all provide their own implementations for A's virtual function g which is used to modify its callers internal state. Furthermore all derivative classes B_i implement a function f which calls B_i's implementation of A's virtual function g for some number of times.
We'd like to avoid to manually write what is essentially a copy-paste code for all of the derivative classes B_1,...,B_n. To my knowledge you can't solve this problem by defining an appropriate function f_A for the base class A which all derivatives would inherit, as then calling the inherited f_A from any B_i would result in a situation where we'd first traverse to A, and then hope to call B_i's implementation of A's virtual function g, which is impossible as at the moment of calling f we are only aware what A has implemented, and A has not implemented its virtual function g.
Thus my solution is to use association in the derivative classes B_1,...,B_n by providing an external class E which has a templated version of f which can then be used to call any B_i's function g.
Below is an attempt for a small runnable attempt. A is just *A having only one derivative B. A's virtual function is foobar and the the external class is Printer, providing the function printer_print. I also figured that since the call for f should only modify the callers internal state, it is better to wrap the call for Printer to another function in B.
Error message: LNK2019 unresolved external symbol "public: void __thiscall Printer::printer_print(class B *,int)const " (??$printer_print@VB@@@Printer@@QBEXPAVB@@H@Z) referenced in function "public: void __thiscall B::multiprint(int)" (?multiprint@B@@QAEXH@Z) Composition test C:\Users\tapan\source\repos\Composition test\Composition test\B.obj 1
Code:
Main file called "Composition test":
#include "Printer.h"
#include "B.h"
int main()
{
B my_b{};
my_b.multiprint(4);
return 0;
}
Header file of external class Printer:
#pragma once
class Printer
{
public:
template <class T> void printer_print(T* src, int count) const;
};
Source file of external class Printer:
#include "Printer.h"
template<class T> void Printer::printer_print(T* src, int count) const {
for (int i{ 0 }; i < count; ++i) {
src->foobar();
}
}
Header file of base class A:
#pragma once
class A
{
public:
virtual void foobar() = 0;
A(int id, char symbol, bool is_on);
int id{};
char symbol{};
bool is_on{};
};
Source file of base class A
#include "A.h"
A::A(int id, char symbol, bool is_on) : id{ id }, symbol{ symbol }, is_on{ is_on } {}
Header file of derivative class B
#pragma once
#include "A.h"
#include "Printer.h"
class B :
public A
{
public:
B();
void foobar();
void multiprint(int count);
private:
Printer m_printer;
};
Source file of derivative class B
#include <iostream>
#include "B.h"
#include "Printer.h"
B::B() : A{ 0, 'a', true}, m_printer{Printer()} {}
void B::foobar() {
std::cout << "B's foobar!\n";
is_on = !is_on;
}
void B::multiprint(int count) {
m_printer.printer_print<B>(this, count);
}