0

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);
}
Epsilon Away
  • 303
  • 1
  • 8

0 Answers0