1

I have a "chain" class, meaning a class that manages a sequence of objects with a common base class. This chain class should execute the member function processSample(a, b) for any child class (of baseClass) I add.

I want to be able to code more child classes (with a processSample(a, b) function) later on, and add them to the chain without having to edit the chain class. I could use a template in the add function but this doesn't solve the problem that there is no data structure for different datatypes (of different sizes) right?

Functions of the children called in the Chain class should all be overridden virtuals from the base class.

class baseClass
{
public:

    virtual float processSample(int a, float b)
    {

    }
};


class Chain
{
    const int maxChilds = 20;
    ?sometype? allChilds[maxChilds];

public:
    float processSample(int c, float d)
    {
        for (int i = 0; i < maxChilds; i++)
        {
            input = allChilds[i].processSample(a, b);
        }

        return input;
    }

    void addChild(?sometype? newChild)
    {
       allChilds.push_back(newChild)
    }
}
JaMiT
  • 14,422
  • 4
  • 15
  • 31
audev
  • 31
  • 2
  • 1
    `?sometype?` -> `baseClass *` most likely, but you'll likely want a book-keeping counter of `baseClass`s that are pointed at by `allChilds`. Iterating to `maxChilds` will be fatal if you don't add `maxChilds` instances. – user4581301 Dec 31 '20 at 01:13
  • 4
    Or `std::vector` or `std::vector>`. – ChrisD Dec 31 '20 at 01:16
  • @ChrisD has the right of this. Raw arrays in C++ have no `push_back` method. Or any methods. Arrays are really simple and really dumb. – user4581301 Dec 31 '20 at 01:22
  • Does this answer your question? [Store derived class objects in base class variables](https://stackoverflow.com/questions/8777724/store-derived-class-objects-in-base-class-variables) – JaMiT Dec 31 '20 at 01:41

2 Answers2

2

You would want to use pointers or references, to avoid initialization or copy operations as part of creating the class.

For example

class Chain
{
    const int maxChilds = 20;
    baseClass allChilds[maxChilds];

Will create, and initialize an array of 20 baseClass instances. Whereas this:

class Chain
{
    const int maxChilds = 20;
    baseClass* allChilds[maxChilds];

Will create an array of pointers to baseClass, which can also point to instances of any child classes. Do consider which class will be responsible for allocation and de-allocation of the memory for these instances (this can either be within this class, or the caller / user of this class - which one is ideal will depend on the rest of your design). You could also consider using a smart pointer instead and let that manage the memory for you: https://en.cppreference.com/book/intro/smart_pointers

Similarly:

void addChild(baseClass newChild)

Will use pass-by-value to pass in a copy of newChild (using the copy constructor of baseClass), any instances of child classes will either fail or be converted to an instance of baseClass. Whereas if you instead go with:

void addChild(baseClass& newChild)

It will use pass-by-reference instead, and the function will receive a reference to the original object.

Adam Luchjenbroers
  • 4,917
  • 2
  • 30
  • 35
  • 2
    Note that for `addChild` to truly work, you have to make absolutely certain that the lifetime of the node added matches or exceeds the lifetime of the `Chain`. Often you need [a clone method](https://stackoverflow.com/questions/24939570/how-to-clone-as-derived-object-in-c) to create an instance with a longer life and `Chain` takes ownership of it. – user4581301 Dec 31 '20 at 01:20
  • Yes - there's plenty of other bugs in the code to be fixed :). I figured I'd stick to just addressing the question as asked, especially since the copy constructor / pass-by-value behaviour is an important difference to understand for someone coming from something like Java where everything is pass-by-reference. – Adam Luchjenbroers Dec 31 '20 at 02:10
0

The nice effect of virtual is, that you "call a function of the base class", but the function of the derived class will be executed.

So ?sometype? allChilds[maxChilds]; is baseClass allChilds[maxChilds];. The chain should be the holder of the objects, so addChild(...) should not accept an instance of the child-class. It should create the instance and use (if necessary) std::move to add it to the array.

Remark: It will be easier for you using

std::vector<baseClass>allChilds;
allChilds.reserve(maxChilds); //reserves the memory but you can still use push back
UweJ
  • 447
  • 3
  • 10