Killercam Killercam - 3 months ago 16
C++ Question

Abstract Class Hierarchy and Access Violation

The background to this is that I am attempting to re-factor a complex C++ application. I have put together the code below as a trimmed down version of the code I am working with (cutting out the irrelevent methods etc.). I am probably doing something stupid as I have not touched C++ in years, but I can see what...

I have the following classes

message_sink.h:

class IMessageSink
{
public:
virtual ~IMessageSink() { };
virtual void process(const Message& msg) = 0;
};


with the following base class

model_base.h:

class Model : public virtual IMessageSink
{
public:
Model(Tag newObsTag);

virtual Model* makeA(Tag newObsTag) = 0;
virtual Model* makeB(Tag newObsTag) = 0;

void process(const Message msg);

void setH00(double v) { _H00 = v; }
void reset();

private:
friend class ModelEM;

const Tag _newObsTag;
virtual void calculatePdf(double lambda, Probability& p) = 0;
};


where model_base.cpp is

#include "model_base.h"
#include <cmath>
...
#include "utility/time.h"

Model::Model(Tag newObsTag) : _newObsTag(newObsTag) { }

void Model::reset()
{
// ... some implementation
}

void Model::process(const Message msg)
{
// ... some implementation
}


I then have the following classes inheriting from the base class

model_m0.h:

class ModelM0 : public virtual Model
{
public:
ModelM0(Tag newObsTag);

ModelM0* makeA(Tag newObsTag); // I can return ModelM0* due to substitution principle
ModelM0* makeB(Tag newObsTag); // I can return ModelM0* due to substitution principle

private:
void calculatePdf(double lambda, Probability& p);
};


model_m0.cpp:

#include "model_m0.h"
#include <cmath>
...
#include "utility/time.h"

ModelM0::ModelM0(Tag newObsTag) : Model(newObsTag) { }

ModelM0* ModelM0::makeA(Tag newObsTag)
{
ModelM0* m = new ModelM0(newObsTag);

m->setH00(std::pow(10.0, -3.342));
m->reset();

return m;
}

ModelM0* ModelM0::makeB(Tag newObsTag)
{
ModelM0* m = new ModelM0(newObsTag);

m->setH00(std::pow(10.0, -3.002));
m->reset();

return m;
}

void ModelM0::calculatePdf(double lambda, Probability& p)
{
Poisson dist(lambda);
for (int n = 0; n != p.size(); ++n)
p.setAction(n, dist.cdf(n));
}


But here is where the problems lies, I have another class called
ModelM0Holder
and this is defined as

model_m0_holder.h:

class ModelM0Holder : public IMessageSink
{
public:
static ModelM0Holder* make(Tag newObsTag)
{
return new ModelM0Holder(newObsTag);
}

ModelM0Holder(Tag newObsTag);
~ModelM0Holder();

void process(const Message& msg);

private:
ModelM0* getModel(int line);

const tau::Period _period;
std::map<int, ModelM0*> _lineMap;
};


and model_m0_holder.cpp: is

ModelM0Holder::ModelM0Holder(Tag newObsTag) : _newObsTag(newObsTag) { }

ModelM0Holder::~ModelM0Holder()
{
// ... some implementation
}

void ModelM0Holder::process(const Message& msg)
{
// ... some implementation
}

ModelM0* ModelM0Holder::getModel(int ag)
{
std::map<int, ModelM0*>::iterator i = _lineMap.find(ag);
if (i == _lineMap.end())
{
ModelM0* m;

if (_period == tau::PERIOD_A)
m = m->makeA(_newObsTag); // Access Violation Exception.
else
m = m->makeB(_newObsTag);

...
}
return i->second;
}


When I call
ModelM0Holder::getModel
I get an
AccessViolationException
, I can't call this function, why?

Thanks very much for your time.

Answer

You can't do m-> when m is unitialized. That will access a random memory location (and cause a dump).

If I understand the intention of your code correctly, you can make makeA and makeB static.

class ModelM0 : public virtual Model
{
public:
    . . .    
    static ModelM0* makeA(Tag newObsTag);
    static ModelM0* makeB(Tag newObsTag);
    . . .    
};

Then change getModel to look like this:

    ModelM0* m;

    if (_period == tau::PERIOD_A)
        m = ModelM0::makeA(_newObsTag);
    else
        m = ModelM0::makeB(_newObsTag);