How do I override a public member function of a juce voice? - c++

Hi I am coding a synth in the Juce framework.
When my adsr is running I need to override isVoiceActive() and set it to true from inside the voice. This is a public member function of the SynthesiserVoice class.
virtual bool SynthesiserVoice::isVoiceActive ( ) const
Returns true if this voice is currently busy playing a sound.
By default this just checks the getCurrentlyPlayingNote() value, but
can be overridden for more advanced checking.
So in the voice I have another member function virtual void renderNextBlock() and from inside it I want to override isVoiceActive
class SynthVoice : public SynthesiserVoice
{
public:
void renderNextBlock (AudioBuffer <float> &outputBuffer, int startSample, int numSamples) override
{
for (int sample = startSample; sample < (startSample + numSamples); ++sample)
{
float env_value = adsr.getNextSample();
if(env_value > 0)
isVoiceActive = true; //???????
...

you cannot do this because isVoiceActive is not an attribute it's a function, you can use your isVoiceActive as a data member and not as a function member so you can assign it true or false. or if you want to work with function then you have to add '&' so you can assign to that function a value (if you don't use '&' then you cannot do what you want to do.
you have 2 choices:
1/ to use isVoiceActivat as a data member and you can do like this:
class SynthesiserVoice
{
public:
bool isVoiceActive;
};
class SynthVoice :public SynthesiserVoice
{
public:
oid renderNextBlock (AudioBuffer <float> &outputBuffer, int startSample, int numSamples) override
{
for (int sample = startSample; sample < (startSample + numSamples); ++sample)
{
float env_value = adsr.getNextSample();
if(env_value > 0)
isVoiceActive = true;
}
}
};
2/ to do the following:
class SynthesiserVoice
{
public:
bool i = false;
virtual bool& isVoiceActive() { return i; } // or virtual bool& isVoiceActive()=0;
};
class SynthVoice :public SynthesiserVoice
{
public:
bool& isVoiceActive()override { return i; }
void renderNextBlock (AudioBuffer <float> &outputBuffer, int startSample, int numSamples) override
{
for (int sample = startSample; sample < (startSample + numSamples); ++sample)
{
float env_value = adsr.getNextSample();
if(env_value > 0)
isVoiceActive ()= true;
}
}
};
Now you have to implement this to suit your functions and data.
Hope it's clear and helpful

Related

Is this member variable used to register subclasses in this protype design pattern? If yes, how?

I am studying this piece of code in the book "Design Patterns explained simply".
It is the implementation of proytpe design pattern by the author Alexander Shvets.
Although I thikn I have undrstand most of it, but the static variable _landSatImage have confued me for several days.
By the comment of the author, it seems to register the subclass.
But how _landSatImage is used to register the subclasses?
Anyone can give me some clue? Thanks :)
#include <iostream>
#include <vector>
using namespace std;
//--------------------- 1 Image
enum imageType
{
LSAT, SPOT
};
class Image
{
public:
virtual void draw() = 0;
static Image *findAndClone(imageType);
protected:
virtual imageType returnType() = 0;
virtual Image *clone() = 0;
// As each subclass of Image is declared, it registers its prototype
static void addPrototype(Image *image)
{
_prototypes[_nextSlot++] = image;
}
private:
static Image *_prototypes[10];
static int _nextSlot;
};
Image *Image::_prototypes[];
int Image::_nextSlot;
// Client calls this public static member function
// when it needs an instance of an Image subclass
Image *Image::findAndClone(imageType type)
{
for (int i = 0; i < _nextSlot; i++)
if (_prototypes[i]->returnType() == type)
return _prototypes[i]->clone();
}
//----------------------- 2 LandSatImage
class LandSatImage: public Image
{
public:
imageType returnType()
{
return LSAT;
}
void draw()
{
cout << "LandSatImage::draw " << _id << endl;
}
// When clone() is called, call the one-argument ctor with a dummy arg
Image *clone()
{
return new LandSatImage(1);
}
protected:
// This is only called from clone()
LandSatImage(int dummy)
{
_id = _count++;
}
private:
// Mechanism for initializing an Image subclass -
// this causes the default ctor to be called,
// which registers the subclass's prototype
static LandSatImage _landSatImage;
// This is only called
// when the private static data member
// is inited
LandSatImage()
{
addPrototype(this);
}
// Nominal "state" per instance mechanism
int _id;
static int _count;
};
// Register the subclass's prototype
LandSatImage LandSatImage::_landSatImage;
// Initialize the "state" per instance mechanism
int LandSatImage::_count = 1;
//------------------------------ 3 SpotImage
class SpotImage: public Image
{
public:
imageType returnType()
{
return SPOT;
}
void draw()
{
cout << "SpotImage::draw " << _id << endl;
}
Image *clone()
{
return new SpotImage(1); //
}
protected:
SpotImage(int dummy)
{
_id = _count++;
}
private:
SpotImage()
{
addPrototype(this);
}
static SpotImage _spotImage;
int _id;
static int _count;
};
SpotImage SpotImage::_spotImage;
int SpotImage::_count = 1;
//----------------------------------------- main
// Simulated stream of creation requests
const int NUM_IMAGES = 8;
imageType input[NUM_IMAGES] =
{
LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT
};
int main()
{
Image *images[NUM_IMAGES];
// Given an image type, find the right prototype, and return a clone
for (int i = 0; i < NUM_IMAGES; i++)
images[i] = Image::findAndClone(input[i]);
// Demonstrate that correct image objects have been cloned
for (int i = 0; i < NUM_IMAGES; i++)
images[i]->draw();
// Free the dynamic memory
for (int i = 0; i < NUM_IMAGES; i++)
delete images[i];
}

How can I use a QMap to store and look at my data?

I am new to QT started to try out some things with QMap as it seems like a useful tool. I already read some other forum threads but I wasnt able to answer my question. The user is supposed to add and edit different shapes via the GUI. For the shapes I first wrote an abstract base class:
#ifndef BASE_H
#define BASE_H
#include <QListWidget>
#include <QMap>
class Base
{
protected:
QVariantMap m_properties;
QString m_key;
void setKey(const QString& key){
this->m_key=key;
}
public:
Base(){}
virtual ~Base(){}
QString key(){
return m_key;
}
void setProperty(QString key, QVariant variant){
m_properties[key]=variant;
}
virtual void toRTC()=0;
};
#endif // BASE_H
one example of a subclass is an ellipse with the following cpp file:
#include "ellipse.h"
Ellipse::Ellipse(int Start_x, int Start_y, int Rad_x, int Rad_y): rad_x(Rad_x), rad_y(Rad_y), start_x(Start_x), start_y(Start_y)
{
this->setKey("ellipse");
this->setProperty("radX", rad_x);
this->setProperty("radY", rad_y);
this->setProperty("startX", start_x);
this->setProperty("startY", start_y);
}
void Ellipse::set_rad_x(int rad_x)
{
Base::setProperty("radX", rad_x);
}
void Ellipse::set_rad_y(int rad_y)
{
Base::setProperty("radY", rad_y);
}
void Ellipse::set_start_x(int start_x)
{
Base::setProperty("startX", start_x);
}
void Ellipse::set_start_y(int start_y)
{
Base::setProperty("startY", start_y);
}
int Ellipse::get_rad_x()
{
return m_properties["radX"].toInt();
}
int Ellipse::get_rad_y()
{
return m_properties["radY"].toInt();
}
int Ellipse::get_start_x()
{
return m_properties["startX"].toInt();
}
int Ellipse::get_start_y()
{
return m_properties["startY"].toInt();
}
First off, is this a correct approach for the cpp file? I feel my approach is vary laborious.
In my main window file I thought about storing my data in a simple Vector QVector<Base *> data_storage;
Ellipse *e_values = new Ellipse(ui->Ellipse_Value_start_x->value(),ui->Ellipse_Value_start_y->value(), ui->Ellipse_Value_rad_x->value(),ui->Ellipse_Value_rad_y->value());
data_storage.append(e_values);
To load the data, I thought it would be a good idea to use the key to check which object of data_storage I want to load, but I don't really know how I can access the data which is connected to my key.
if(data_storage[t]->key()=="ellipse"){
ui->Ellipse_Value_rad_x->setValue(data_storage[t]->) //how can I access the correct data?
}
I feel like I messed up the entire approach, like how to properly use keys, so how would I do that?
You need to declare all the behaviours you need in the base class. I don't see the need to have Base hold the data.
E.g. if you need to be able to read and write the UI, there should be methods to do that.
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void writeUI(form_t * ui) const = 0;
virtual void readUI(const form_t * ui) = 0;
};
class Ellipse : public Base
{
int start_x;
int start_y;
int rad_x;
int rad_y;
public:
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void writeUI(form_t * ui) const final {
ui->Ellipse_Value_rad_x->setValue(rad_x);
ui->Ellipse_Value_rad_y->setValue(rad_y);
ui->Ellipse_Value_start_x->setValue(start_x);
ui->Ellipse_Value_start_y->setValue(start_y);
}
void readUI(const form_t * ui) final {
rad_x = ui->Ellipse_Value_rad_x->value().toInt();
rad_y = ui->Ellipse_Value_rad_y->value().toInt();
start_x = ui->Ellipse_Value_start_x->value().toInt();
start_y = ui->Ellipse_Value_start_y->value().toInt();
}
};
If you don't want to tie your shapes to the UI, you could define a visitor interface, with a visit method for each shape type.
class ShapeVisitor
{
virtual void accept(Ellipse * ellipse) = 0;
/* virtual void accept(Rectangle * rectangle) = 0; // etc.. */
};
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void visit(ShapeVisitor & visitor) = 0;
};
class Ellipse : public Base
{
public:
int start_x;
int start_y;
int rad_x;
int rad_y;
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void visit(ShapeVisitor & visitor) final {
visitor.accept(this); // calls visitor::accept(Ellipse *)
}
};
class UIReadVisitor : public ShapeVisitor
{
form_t * ui
void accept(Ellipse * ellipse) final {
ellipse->rad_x = ui->Ellipse_Value_rad_x->value().toInt();
ellipse->rad_y = ui->Ellipse_Value_rad_y->value().toInt();
ellipse->start_x = ui->Ellipse_Value_start_x->value().toInt();
ellipse->start_y = ui->Ellipse_Value_start_y->value().toInt();
}
}
class UIWriteVisitor : public ShapeVisitor
{
form_t * ui;
void accept(Ellipse * ellipse) final {
ui->Ellipse_Value_rad_x->setValue(ellipse->rad_x);
ui->Ellipse_Value_rad_y->setValue(ellipse->rad_y);
ui->Ellipse_Value_start_x->setValue(ellipse->start_x);
ui->Ellipse_Value_start_y->setValue(ellipse->start_y);
}
}

GoogleTest Mocking object method call fail

Hi so this is my first time utilizing googleTest Mocking. The general setup of the project is that coffeeMachine has an object coffeeStorage and coffeeStockService that it calls methods from coffeeMachine methods. I'm trying to create a mock test for the objects coffeeStorage and coffeeStockService but it's not recognizing the Expected Calls when I assign the mock objects to the coffeeMachine instance.
Trying to implement GoogleTest's mocking test framework but it's not recognizing the EXPECTED_CALL and also not letting me use mockedCoffeeStorage as a parameter to the method calls for mockedCoffeeStockService.. StockService Expected Call is because CoffeeMachine is also calling that but I passed in the coffeeStorage as a parameter. Is that possible for a mock object to cause a method that is using another mock object as the parameter and still expect the method to be called? Should I refactor and not include all the object references to the methods for CoffeeMachine since I already declare a CofeeStorage and CoffeeStockService object? Thank you so much
class coffeeMachine {
public:
coffeeStorage* CoffeeStorage;
coffeeStockService* CoffeeStockService;
bool coffeeServed = false;
coffeeMachine(coffeeStorage* CoffeeStorage, coffeeStockService* CoffeeStockService);
void start(string langIn);
void stop();
void descale();
void showSettings();
void hideSettings();
map<string, string> getSetting();
string message(coffeeStorage& CoffeeStorage);
void takeCoffee(coffeeStorage& CoffeeStorage);
void fillTank(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService);
void fillBeans(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService);
void emptyGrounds(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService);
bool isDescalingNeeded();
class coffeeStorage {
private:
int waterStorage;
int beanStorage;
int trashStorage;
public:
//virtual ~coffeeStorage(){}
coffeeStorage();
virtual void takeCoffeeStorage();
virtual void setWaterStorage(int amount);
virtual void setBeansStorage(int amount);
virtual void emptyTrashStorage();
virtual int checkWater();
virtual int checkBeans();
virtual int checkTrashStorage();
};
class mockCoffeeStorage : public coffeeStorage {
private:
int waterStorage;
int beanStorage;
int trashStorage;
public:
MOCK_METHOD(void, takeCoffeeStorage, (), (override));
MOCK_METHOD(void, setWaterStorage, (int amount), (override));
MOCK_METHOD(void, setBeansStorage, (int amount), (override));
MOCK_METHOD(void, emptyTrashStorage, (), (override));
MOCK_METHOD(int, checkWater, (), (override));
MOCK_METHOD(int, checkBeans, (), (override));
MOCK_METHOD(int, checkTrashStorage, (), (override));
};
coffeeMachine::coffeeMachine(coffeeStorage* CoffeeStorage_, coffeeStockService* CoffeeStockService_){
waterHardness = "2";
grinder = "medium";
started = false;
coffeeServed = false;
settingsDisplayed = false;
CoffeeStorage = CoffeeStorage_;
CoffeeStockService = CoffeeStockService_;
message(*CoffeeStorage_);
descale();
fillTank(*CoffeeStorage_, *CoffeeStockService_);
fillBeans(*CoffeeStorage_, *CoffeeStockService_);
emptyGrounds(*CoffeeStorage_, *CoffeeStockService_);
}
string coffeeMachine::message(coffeeStorage& CoffeeStorage){
if(!started) return "";
if (settingsDisplayed) return i18n("settings");
if (CoffeeStorage.checkWater() <= 10) return i18n("tank");
if (CoffeeStorage.checkBeans() < 3) return i18n("beans");
if (CoffeeStorage.checkTrashStorage() >= 30) return i18n("grounds");
if (isDescalingNeeded()) return i18n("descale");
return i18n("ready");
}
void coffeeMachine::takeCoffee(coffeeStorage& CoffeeStorage){
if (CoffeeStorage.checkWater() == 0 || CoffeeStorage.checkBeans() == 0) {
coffeeServed = false;
} else {
coffeeServed = true;
CoffeeStorage.takeCoffeeStorage();
countdownToDescale -= 1;
}
}
void coffeeMachine::fillTank(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService){
CoffeeStockService.restockWater(CoffeeStorage);
}
void coffeeMachine::fillBeans(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService){
CoffeeStockService.restockBeans(CoffeeStorage);
}
void coffeeMachine::emptyGrounds(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService){
CoffeeStockService.emptyTrash(CoffeeStorage);
}
TEST(MockObjTest, TestObjectCallsWithMock) {
mockCoffeeStorage mockedCoffeeStorage;
mockCoffeeStockService mockedCoffeeStockService;
EXPECT_CALL(mockedCoffeeStorage, checkWater())
.Times(AtLeast(1));
EXPECT_CALL(mockedCoffeeStorage, checkBeans())
.Times(AtLeast(1));
EXPECT_CALL(mockedCoffeeStorage, takeCoffeeStorage())
.Times(AtLeast(1));
coffeeMachine coffeeTest = coffeeMachine(&mockedCoffeeStorage, &mockedCoffeeStockService);
std::cout<< "Address of mockedCoffeeStorage: " << &mockedCoffeeStorage << "\n";
std::cout<< "Address of mockedCoffeeStockService: " << &mockedCoffeeStockService << "\n";
// EXPECT_CALL(mockedCoffeeStockService, restockWater(mockedCoffeeStorage))
// .Times(AtLeast(1));
// EXPECT_CALL(mockedCoffeeStockService, restockBeans(mockedCoffeeStorage))
// .Times(AtLeast(1));
// EXPECT_CALL(mockedCoffeeStockService, emptyTrash(mockedCoffeeStorage))
// .Times(AtLeast(1));
coffeeTest.start("en");
for(int i = 0; i < 10; i++)
{
if(coffeeTest.getBeansContent(mockedCoffeeStorage) < 5)
coffeeTest.fillBeans(mockedCoffeeStorage, mockedCoffeeStockService);
if(coffeeTest.getGroundsContent(mockedCoffeeStorage) > 20)
coffeeTest.emptyGrounds(mockedCoffeeStorage, mockedCoffeeStockService);
if(coffeeTest.getTankContent(mockedCoffeeStorage) < 15)
coffeeTest.fillTank(mockedCoffeeStorage, mockedCoffeeStockService);
coffeeTest.takeCoffee(mockedCoffeeStorage);
}
}
It's perfectly fine to set expect calls one mock with other mock as a parameter.
no need to pass the objects to each method - you can access them inside your functions because they're are members. This technique is called 'dependency injection'.
See this code (using GMock 1.8, so mock definition is slightly different):
// pure virt. interface, remember about virtual dtor
class coffeeStorage {
public:
virtual ~coffeeStorage() = default;
virtual void takeCoffeeStorage() = 0;
virtual void setWaterStorage(int amount) = 0;
virtual void setBeansStorage(int amount) = 0;
virtual void emptyTrashStorage() = 0;
virtual int checkWater() = 0;
virtual int checkBeans() = 0;
virtual int checkTrashStorage() = 0;
};
class coffeeStockService {
public:
virtual ~coffeeStockService() = default;
virtual void restockWater(coffeeStorage& storeage) = 0;
};
class coffeeMachine {
public:
coffeeMachine(coffeeStorage* CoffeeStorage, coffeeStockService* CoffeeStockService);
void fillTank() {
CoffeeStockService->restockWater(*CoffeeStorage);
}
void takeCoffee() {
if (CoffeeStorage->checkWater() == 0 || CoffeeStorage->checkBeans() == 0) {
coffeeServed = false;
}
else {
coffeeServed = true;
CoffeeStorage->takeCoffeeStorage();
}
}
bool isCoffeeServed() {
return coffeeServed;
}
private:
coffeeStorage* CoffeeStorage;
coffeeStockService* CoffeeStockService;
bool coffeeServed{false};
};
coffeeMachine::coffeeMachine(coffeeStorage* CoffeeStorage_, coffeeStockService* CoffeeStockService_)
: CoffeeStorage{CoffeeStorage_}
, CoffeeStockService{CoffeeStockService_} {}
class mockCoffeeStorage : public coffeeStorage {
public:
MOCK_METHOD0(takeCoffeeStorage, void());
MOCK_METHOD1(setWaterStorage, void(int amount));
MOCK_METHOD1(setBeansStorage, void(int amount));
MOCK_METHOD0(emptyTrashStorage, void());
MOCK_METHOD0(checkWater, int());
MOCK_METHOD0(checkBeans, int());
MOCK_METHOD0(checkTrashStorage, int());
};
class mockCoffeeStockService : public coffeeStockService {
public:
MOCK_METHOD1(restockWater, void(coffeeStorage& storeage));
};
struct MockObjTest : public testing::Test {
mockCoffeeStorage mockedCoffeeStorage;
mockCoffeeStockService mockedCoffeeStockService;
coffeeMachine coffeeTest = coffeeMachine(&mockedCoffeeStorage, &mockedCoffeeStockService);
};
TEST_F(MockObjTest, When_FillingTank_Then_RestocksWater) {
// assert
EXPECT_CALL(mockedCoffeeStockService, restockWater(testing::Ref(mockedCoffeeStorage)));
// act
coffeeTest.fillTank();
}
TEST_F(MockObjTest, Given_NoWater_When_TakingCoffee_Then_CoffeeNotServed) {
// arrange
EXPECT_CALL(mockedCoffeeStorage, checkWater()).WillOnce(testing::Return(0));
// act
coffeeTest.takeCoffee();
// assert
ASSERT_FALSE(coffeeTest.isCoffeeServed());
}
TEST_F(MockObjTest, Given_EnoughWaterWaterAndBeans_When_TakingCoffee_Then_takeCoffeeStorageAndCoffeeServed) {
// arrange
EXPECT_CALL(mockedCoffeeStorage, checkWater()).WillOnce(testing::Return(1));
EXPECT_CALL(mockedCoffeeStorage, checkBeans()).WillOnce(testing::Return(1));
EXPECT_CALL(mockedCoffeeStorage, takeCoffeeStorage()); // this is more of the 'assert' part, but it cannot be moved to the end of the test
// act
coffeeTest.takeCoffee();
// assert
ASSERT_TRUE(coffeeTest.isCoffeeServed());
}
This is trimmed and simplified version of your code, but this should get you running. Always try to start with some v. easy, minimal test and build from this adding more complexity. If the tests becomes too complex/complicated, it is probably time to separate some parts of your code to the new class and test this class in separation.

Automatically decide which class to use for data processing

I have a big project where I faced a problem, which can be shortly formulated as following:
I had a class which is created temporally and used to process and modify some data (let's call it "worker"). Now I have two workers and two corresponding data formats. The data array can contain mixed data, how to make my programm automatically decide which worker class it should create and use for data processing? How to make this in the best way?
To illustrate this problem I wrote small example programm, which is analogical to my project.
#include <iostream>
#include <vector>
using namespace std;
const int NInputs = 10;
struct TOutput {
int i;
};
class TProcess {
public:
TProcess( const vector<TInput>& i ){ fInput = i; }
void Run();
void GetOutput( TOutput& o ) { o = fOutput; }
private:
vector<TInput> fInput;
TOutput fOutput;
};
#if 0
struct TInput {
int i;
};
class TWorker{
public:
void Init( int i ) { fResult = i; }
void Add( int i ) { fResult += i; }
int Result() { return fResult; }
private:
int fResult;
};
#else
struct TInput {
int i;
};
class TWorker {
public:
void Init( int i ) { fResult = i; }
void Add( int i ) { fResult ^= i; }
int Result() { return fResult; }
private:
int fResult;
};
#endif
void TProcess::Run() {
TWorker worker;
worker.Init(0);
for( int i = 0; i < fInput.size(); ++i )
worker.Add(fInput[i].i);
fOutput.i = worker.Result();
}
int main() {
vector<TInput> input(NInputs);
for ( int i = 0; i < NInputs; i++ ) {
input[i].i = i;
}
TProcess proc(input);
proc.Run();
TOutput output;
proc.GetOutput(output);
cout << output.i << endl;
}
The example is very simple, but that doesn't means that it's simply possible to transform it to one function --- it corresponds to big project. Therefore it is not possible to:
delete classes or functions, which already exists (but possible to modify them and create new)
make workers static or create only one copy of worker (each workers are temporary in many complicated functions and loops)
So how to modify it such that this will be something like this:
// TODO: TProcess declaration
struct TInput1 {
int i;
};
class TWorker1{
public:
void Init( TInput1 i ) { fResult = i; }
void Add( TInput1 i ) { fResult += i.i; }
int Result() { return fResult; }
private:
int fResult;
};
#else
struct TInput2 {
int i;
};
class TWorker2 {
public:
void Init( TInput2 i ) { fResult = i.i; }
void Add( TInput2 i ) { fResult ^= i.i; }
int Result() { return fResult; }
private:
int fResult;
};
void TProcess::Run() {
for( int i = 0; i < fInput.size(); ++i ) {
// TODO: choose and create a worker
worker.Add(fInput[i].i);
// TODO: get and save result
}
fOutput.i = worker.Result();
}
int main() {
vector<TInputBase> input(NInputs);
// TODO: fill input
TProcess proc(input);
proc.Run();
TOutput output;
proc.GetOutput(output);
cout << output.i << endl;
}
My initial idea was to use basic class and template functions, but there is no template virtual functions...
You've got the right idea with the vector<TInputBase> declaration in your second example -- you need to have a common base class for all inputs, and similarly for all workers:
class TInput {
}
class TInput1 : public TInput { ... }
class TInput2 : public TInput { ... }
class TWorker {
public:
void Init(TInput *input) = 0;
void Add(TInput *input) = 0;
int Result() = 0;
}
class TWorker1 : public TWorker { ... }
class TWorker2 : public TWorker { ... }
Note, however, that this means all workers can only take a TInput * as input and you will need to cast to the correct input class inside each worker class.
The simplest way to decide which worker class to use for a given input is to ask the input itself! You can have a virtual function in the input class that creates the right kind of worker:
class TInput {
virtual TWorker *createWorker() = 0;
}
class TInput1 : public TInput {
TWorker *createWorker() {
return new TWorker1();
}
}
class TInput2 : public TInput {
TWorker *createWorker() {
return new TWorker2();
}
}
If this is not possible for some reason, you can use typeid to determine the type of the input and create a corresponding worker instance.

Confusing segmentation fault

EDIT: I basically revamped the whole question so I could provide an executable example...
I have been getting a segmentation fault that I can't figure out. Here is a compacted version of my code. I maintained the original class hierarchy even though some of the classes have no relevant methods since I think that it has something to do with my issue, especially after some of the comments I've been getting.
#import <vector>
using namespace std;
template<class Data = float>
class Vector
{
// All pure virtual functions.
};
template<class Data>
class TranslationVector : public virtual Vector<Data>
{
// All pure virtual functions.
};
template<class Data>
class SimpleVector4 : public virtual Vector<Data>
{
public:
SimpleVector4(const Data d0, const Data d1, const Data d2, const Data d3)
{
fData = new vector<Data> ;
fData->push_back(d0);
fData->push_back(d1);
fData->push_back(d2);
fData->push_back(d3);
}
vector<Data>*
getData()
{
return (fData);
}
private:
vector<Data>* fData;
};
template<class Data>
class SimpleTranslationVector4 : public SimpleVector4<Data> , public TranslationVector<Data>
{
public:
SimpleTranslationVector4(const Data x, const Data y, const Data z, const Data w) :
SimpleVector4<Data> (x, y, z, w)
{
}
};
template<class Data = float>
class Matrix
{
// All pure virtual functions.
};
template<class Data>
class TransformationMatrix : public virtual Matrix<Data>
{
// All pure virtual functions.
virtual void
translate(TranslationVector<Data>* const translation) = 0;
};
template<class Data>
class SimpleMatrix44 : public virtual Matrix<Data>
{
public:
SimpleMatrix44()
{
fData = new vector<Data> (CELLS_IN_MATRIX, 0);
setIdentity();
}
vector<Data>*
getData()
{
return (fData);
}
void
setIdentity()
{
fData->at(0) = 1;
fData->at(1) = 0;
fData->at(2) = 0;
fData->at(3) = 0;
fData->at(4) = 0;
fData->at(5) = 1;
fData->at(6) = 0;
fData->at(7) = 0;
fData->at(8) = 0;
fData->at(9) = 0;
fData->at(10) = 1;
fData->at(11) = 0;
fData->at(12) = 0;
fData->at(13) = 0;
fData->at(14) = 0;
fData->at(15) = 1;
}
private:
static const int CELLS_IN_MATRIX = 16;
vector<Data>* fData;
};
template<class Data>
class SimpleTransformationMatrix44 : public SimpleMatrix44<Data> , public TransformationMatrix<Data>
{
public:
SimpleTransformationMatrix44() :
SimpleMatrix44<Data> ()
{
}
void
translate(TranslationVector<Data>* translation)
{
vector<Data> *data = SimpleMatrix44<Data>::getData();
vector<Data> *transData = ((SimpleVector4<Data>*) translation)->getData();
// The error occurs on this line:
data->at(12) += data->at(0) * transData->at(0) + data->at(4) * transData->at(1) + data->at(8) * transData->at(2);
data->at(13) += data->at(1) * transData->at(0) + data->at(5) * transData->at(1) + data->at(9) * transData->at(2);
data->at(14) += data->at(2) * transData->at(0) + data->at(6) * transData->at(1) + data->at(10) * transData->at(2);
data->at(15) += data->at(3) * transData->at(0) + data->at(7) * transData->at(1) + data->at(11) * transData->at(2);
}
};
int
main(int argc, char** argv)
{
SimpleTransformationMatrix44<float> matrix1;
matrix1.translate(new SimpleTranslationVector4<float> (0.0f, 10.0f, 0.0f, 1.0f));
return 0;
}
I have commented in the code where the error occurs. From debugging I can see that it actually occurs in the size() function of vector and that transData has not been initialized. I can't for the life of me figure out why transData has not been initialized! Any ideas?
Thanks,
Gaz.
Cast of non-inherited classes seems to be your error.
Let's see your code. There is a conversion of SimpleTranslationVector4<float>* to TranslationVector<float>* while invoking the translate function. Then the converted value is converted again into SimpleVector4<float>*. But the SimpleVector4<float> does not inherit TranslationVector<float>.
This code also results in error.
template<class Data>
class SimpleVector4 {
public:
int a;
};
template<class Data>
class TranslationVector {
};
template<class Data>
class SimpleTranslationVector4 : public SimpleVector4<Data>,
public TranslationVector<Data> {
};
int main() {
SimpleTranslationVector4<float> A;
SimpleVector4<float>* b = (SimpleVector4<float>*)&A;
TranslationVector<float>* c = (TranslationVector<float>*)&A;
SimpleVector4<float>* d = (SimpleVector4<float>*)c;
b->a = 1; // ok
d->a = 1; // error
}
You're doing a C-style cast between unrelated types. This is not safe. The fact that you need to do this at all probably indicates a problem in your design, but try replacing this:
vector<Data>* transData = ((SimpleVector4<Data>*) translation)->SimpleVector4<Data>::getData();
with this:
vector<Data>* transData = dynamic_cast<SimpleVector4<Data>*>(translation)->getData();