Background:
I come from a C background and just started using C++ for embedded projects.
I have written a single firmware that is able to handle multiple devices, depending on how it is configured via a graphical interface before the end user gets the device.
Each device type is represented by a class.
Many parameters are shared across multiple (but not all) types of devices (i.e. battery level), and some functions as well (i.e. read something from EEPROM which is device-type specific).
Goal:
To be able to access functions and variables through a pointer without having to cast the void pointer constantly.
Shouldn't I know what type of device I am using before calling a function?
Well yes I do, but let's consider the following.
void * _type;
uint8_t deviceType = getDeviceTypeFromEEPROM();
//somewhere at the beginning
switch(deviceType)
{
case DEVICE_A:
_type = new DeviceA();
break;
case DEVICE_B:
_type = new DeviceB();
break;
}
//somewhere during execution.
//I want to avoid having to do something like this. 2 types in example, in reality I have over 10.
//I would prefer not to put a switch and cast every time I need flexibility.
switch(deviceType)
{
case DEVICE_A:
static_cast<DeviceA*>(_type)->readEEPROM();
break;
case DEVICE_B:
static_cast<DeviceB*>(_type)->readEEPROM();
break;
}
Contemplated Solution:
Have a base class and using virtual functions. What about variables? Would I need to have virtual functions to access the variables that reside in the different classes?
Other Solutions:
Open to any alternative solutions.
Here's a sketch of how I might implement an OOP-style solution; nothing fancy, just an enumeration of the different types of parameter your program supports, and an IDevice interface that represents any device that knows how to set or get values of those types. Then you can implement subclasses as necessary for devices with parameters that are specific to that device type:
enum class ParameterType {
BatteryLevel,
Uptime,
SerialNumber,
DeviceAProprietarySetting,
DeviceBProprietarySetting,
// [... add more values here as necessary...]
};
typedef std::variant<int, float, std::string> ParameterValue;
// Abstract interface to any device
// (so you can pass around IDevice* pointers instead of void* pointers)
class IDevice
{
public:
IDevice() {}
virtual ~IDevice() {}
/** Subclass should implement this to write the specified parameter-value
* into (retValue) and return true... or if it cannot (e.g. because it
* doesn't support that particular parameter-value), it should return
* false to indicate failure.
*/
virtual bool GetValue(ParameterType pt, ParameterValue & retValue) const = 0;
/** Subclass should implement this to accept the specified parameter-value
* from (newValue) and return true... or if it cannot (e.g. because it
* doesn't support that particular parameter-value), it should return
* false to indicate failure to set anything.
*/
virtual bool SetValue(ParameterType pt, const ParameterValue & newValue) = 0;
// more virtual methods could be added here, if there are other actions
// that most of your devices support
};
// Since most devices have these parameters, we'll move them up into a shared
// base class to avoid having to reimplement that functionality for every device
class TypicalDevice : public IDevice
{
TypicalDevice() {}
virtual bool GetValue(ParameterType pt, ParameterValue & retValue) const
{
switch(pt)
{
case ParameterType::BatteryLevel: retValue = _batteryLevel; return true;
case ParameterType::Uptime: retValue = _uptime; return true;
case ParameterType::SerialNumber: retValue = _serialNumber; return true;
default: return false; // ParameterType not found!
}
}
virtual bool SetValue(ParameterType pt, const ParameterValue & newValue)
{
switch(pt)
{
case ParameterType::BatteryLevel: _batteryLevel = std::get<float>(newValue); return true;
case ParameterType::Uptime: _uptime; = std::get<int>(newValue) return true;
case ParameterType::SerialNumber: _serialNumber = std::get<std::string>(newValue); return true;
default: return false; // ParameterType not found!
}
}
private:
float _batteryLevel;
int _uptime; // in seconds?
std::string _serialNumber;
};
// Implementation for some specific device-type
class DeviceA : public TypicalDevice
{
DeviceA() {}
virtual bool GetValue(ParameterType pt, std::variant & retValue) const
{
switch(pt)
{
case ParameterType::DeviceAProprietarySetting: retValue = _deviceAProprietarySetting; return true;
default:
return TypicalDevice::GetValue(pt, retValue);
}
}
virtual bool SetValue(ParameterType pt, const std::variant & newValue)
{
switch(pt)
{
case ParameterType::DeviceAProprietarySetting: _deviceAProprietarySetting = std::get<float>(newValue); return true;
default:
return TypicalDevice::GetValue(pt, retValue);
}
}
private:
float _deviceAProprietarySetting;
};
Related
I thing I'm missing something obvious but here is my problem
with a pure abstract class IFoo
class IFoo
{
public:
virtual bool isBar1() const=0;
virtual bool isBar2() const=0;
};
and 2 implementations
class Foo1 : public IFoo
{
public:
bool isBar1() const override { return true;}
bool isBar2() const override { return false;}
};
class Foo2 : public IFoo
{
public:
bool isBar1() const override { return false;}
bool isBar2() const override { return true;}
};
I have a managing class that must call the right method depending on a variable protocol
class FooManager : public IFoo
{
public:
bool isBar1() const override
{
switch(protocol)
{
case 1: return Foo1().isBar1();
case 2: return Foo2().isBar1();
default: return false;
}
}
bool isBar2() const override
{
switch(protocol)
{
case 1: return Foo1().isBar2();
case 2: return Foo2().isBar2();
default: return false;
}
}
void setProtocol(int proto){this->protocol = proto;}
private:
int protocol{0};
};
But there is a bunch of methods and I don't want to put the switch(protocol)everywhere given that it's really repetitive and new FooX could be added at anytime.
How can I call the right override without using templates (given that protocol is dynamic and FooManager is persistent)
and without using the heap on every call (through smart pointer or the likes because it's for an embedded project where we try to stay on the stack as much as possible).
I can't just create a getFoo() method that return IFoo because it's an abstract class
And I can't return an IFoo& neither because it would return a reference to a temporary.
IFoo& FooManager::getFoo()
{
switch(protocol)
{
case 1: return Foo1();
case 2:
default: return Foo2();
}
//return reference to temporary
}
What else can I do?
You could return a unique_ptr, such as
std::unique_ptr<IFoo> FooManager::getFoo() {
switch (protocol) {
case 1: return std::make_unique<Foo1>();
case 2:
default: return std::make_unique<Foo2>();
}
}
This would result in the data being a pointer and polymorphism being applied on calling the member functions
You can return a std::unique_ptr so you get polymorphic behavior but can control the lifetime of the returned object.
std::unique_ptr<IFoo> FooManager::getFoo()
{
switch(protocol)
{
case 1: return std::make_unique<Foo1>();
case 2:
default: return std::make_unique<Foo2>();
}
}
Since you have a very specific requirement I suggest a very specific solution for this exact problem (which may not be suitable elsewhere). In order to avoid having to use dynamic allocation and pointers or references you can "fake" polymorphism using function pointers. A small example given the requirements you mentioned in your comments:
class Foo {
public:
// function pointer aliases to make them easier to use
// I opted to make the two functions take different parameters for demonstration purposes
using isBar1Func = bool(*)(const Foo*);
using isBar2Func = bool(*)(int);
// constructor requiring the function pointers as parameters
Foo(int value, isBar1Func bar1func, isBar2Func bar2func) :
m_value(value), m_bar1Func(bar1func), m_bar2Func(bar2func) {}
bool isBar1() const {
return m_bar1Func(this);
}
bool isBar2() {
return m_bar2Func(m_value);
}
int getValue() const {
return m_value;
}
private:
int m_value;
isBar1Func m_bar1Func;
isBar2Func m_bar2Func;
};
// example functions to be passed into the constructor
static bool testBar1Func(const Foo* foo) {
return foo->getValue() != 0;
}
static bool testBar2Func(int value) {
return value > 1;
}
// getFoo can simply return a copy
Foo FooManager::getFoo() {
switch (protocol) {
case 1: return Foo(1, testBar1Func, testBar2Func);
// also works with non-capturing lambdas, which can be converted to function pointers
case 2: return Foo(2,
[](const Foo* foo) { return foo->getValue() != 1; },
[](int value) {return value != 12; });
// add remaining cases as desired
}
}
Thanks to #UnholySheep response, here is what I ended with:
class FooManager : public IFoo{
public:
using FooFunc = bool(*)(const IFoo&);
bool callFoo(FooFunc function) const{
switch(protocol) {
case 1: return function(Foo1());
case 2: return function(Foo2());
//and the other cases
}
}
bool isBar1() const override {
return callFoo([](const IFoo& foo){return foo.isBar1();});
}
bool isBar2() const override {
return callFoo([](const IFoo& foo){return foo.isBar2();});
}
};
my FooX classes stay the sames and the switch(protocol) is in a single function meaning that if a new protocol arrives, I just have to create a new FooY for that protocol and add it to the switch to get it working. All that with compile time checks and no use of the heap.
Thanks again #UnholySheep and the others as well.
What would be the most efficient and modern way of handling states in C++ class?
At the moment I am using multiple bools, but the more I states I add the harder is to maintain. For example if I have a class called VideoPlayer and it has four bools defining different states. If we add set methods for each bool we need to unset all the other bools.
class VideoPlayer
{
public:
void play()
{
play_ = true;
pause_ = false;
stop_ = false;
reset_ = false;
}
void stop()
{
stop_ = true;
play_ = false;
pause_ = false;
reset_ = false;
}
private:
bool play_;
bool pause_;
bool stop_;
bool reset_;
};
Your design suffers from it being easy to be in a bad state (e.g. what if both stop_ and play_ are both true?
You should use an enum to define a set of finite-states of which only 1 can be active at any given point in time.
C++'s enum types are somewhat different from Swift, Java and C#'s enum: they're unscoped and are more permissive with implicit conversions - behaving somewhat similarly to #define.
C++11 adds enum class which is very similar to C#'s enum. There is no built-in functionality similar to the flexibility of Java or Swift's enums, however.
You will want something like this:
enum class PlayerState {
Stopped,
Playing,
Paused
}
If Reset is not a state, but a verb, then it should not be in the enum definition.
class VideoPlayer {
private:
PlayerState state;
public:
VideoPlayer() :
state( PlayerState::Stopped )
{
}
void play() {
switch( this->state ) {
case PlayerState::Stopped:
// start video here, only change `state` when complete.
// you might want to add a "BeginPlaying" (e.g. `LoadingFileFromDisk`) state value too.
this->state = PlayerState.Playing;
break;
case PlayerState::Playing:
throw VideoPlayerStateExeception("Already playing");
case PlayerState::Paused:
this->resume();
break;
}
}
}
I would use C++17's std::variant. States will become types with data.
struct Playing {
float time_from_start;
};
struct Paused {
float time_from_start;
};
struct Stopped {};
struct MediaPlayer {
std::variant<
Playing,
Paused,
Stopped
> state;
void play() {
state = Playing{};
}
void pause() {
state.visit([&](auto&& s){
using S = std::decay_t<decltype(s)>;
float time = 0;
if constexpr (std::is_same_v<S, Playing>) {
time = s.time_from_start;
}
state = Paused{time};
});
}
};
One could even add some other useful states:
struct ABLoop {
float a, b, time_from_a;
};
I have a class transition and inside, a member function rate. I am asking for a method that would allow me to insert custom designed rates into instants of transition, after those instants have been created, and would be fast at run-time!
I would like to optimize the code for speed. rate does simple computations but is called very frequently and many times by the program. So I guess I should avoid virtual functions... Question: what are the other best methods to achieve this in C++ (templates,boost,...)? Comments about the speed of a particular method would be appreciated. Thanks!
class transition {
public:
transition() : vec() {}
double rate(T_vec::iterator a) { return ...; }
private:
T_vec vec;
};
/* custom rate #1 */
double my_rate_1( T_vec::iterator) {
/* do something */
return ans;
}
/* custom rate #2 */
double my_rate_2( T_vec::iterator) {
/* do something */
return ans;
}
const int N=10;
int main (void) {
vector<transition*> ts(N);
for(int i=0;i!=N;++i) ts[i] = new transition;
/* How to efficiently implement the pseudo code that follows? */
ts[0]->rate = my_rate_1;
ts[1]->rate = my_rate_2;
/* ... */
}
There are at least three ways to implement this.
Option 1 is virtual methods. You can't bind the method after you create the instance, but after the creation you can treat all the derived classes as transition.
class transition {
...
virtual double rate(T_vec::iterator a) = 0;
};
class my_transition_1 : public transition {
...
double rate(T_vec::iterator a) { ... }
};
class my_transition_2 : public transition {
...
double rate(T_vec::iterator a) { ... }
};
Option 2 is callbacks. You can change the method at runtime, after you created the object. It's the most dynamic. It has slightly higher overhead in this case, because there is an extra copy construction of the iterator, and it is harder for the compiler to optimize away the indirect call.
class transition {
public:
....
typedef double (*RateFunction)(T_vec::iterator a);
void set_rate(RateFunction r) { _fun = r; }
double rate(T_vec::iterator a) { return (*_fun)(a); }
private:
RateFunction _fun;
};
double my_rate_1(T_vec::iterator a) {
...
}
...
transition t;
t.set_rate(my_rate_1);
Option 3 is functor templates. You have to specify everything at construction time, but this avoids the indirect call and has the best performance.
template <typename Rate>
class transition {
double rate(T_vec::iterator a) {
return Rate()(a);
}
};
class my_rate_1 {
double operator()(T_vec::iterator a) {
....
}
};
class my_rate_2 {
double operator()(T_vec::iterator a) {
....
}
};
transition<my_rate_1> t1;
transition<my_rate_2> t2;
Option 4 is not extensible, but you avoid the indirect function call and have the opportunity to set the rate after creating the object.
class transition {
public:
enum RateCode {
RATE_1,
RATE_2,
...
}
double rate(T_vec::iterator i) {
switch (_rate_code) {
case RATE_1: {
...
return result;
}
case RATE_2: {
...
return result;
}
default:
assert(false);
}
}
void setRate(RateCode r) { _rate_code = r; }
private:
RateCode _rate_code;
}
If you want to bind to arbitrary functions, check the FastDelegate article. There is also an article of a more portable implementation of the delegate idea.
If you can arrange your code such that the specific instance is known at compile time, this will be faster, assuming the compiler does its job well. The reason why it is faster is that a true delegate implies a call to a function pointer, and that breaks the speculative execution and pipelining in today's CPU's.
You might also want to read up on C++11. In C++11, lambda functions (inline written functions that can be passed around) are an important extension, and I would expect compilers to work hard to optimize them.
Just a really quick question here. I'm using virtual functions to read in from a text file. Now, it's virtual because in one aspect I want the values to be normalised, and, in the other respect I don't want them to be normalised. I have tried to do this:
bool readwav(string theFile, 'native');
So in theory, if the 'native' is used, this method should be called, however, if 'double' is called then a different version of the method is called. Same for if the value is empty, it should just perform the native option.
First question, why doesn't the declaration above work? Also, is this the best route to go down? Or, would it be better to have just one class method that switches between the options.
Thanks :)
Update:
Where am I going wrong?
bool Wav::readwav(string theFile, ReadType type = NATIVE)
{
// Attempt to open the .wav file
ifstream file (theFile.c_str());
if(!this->readHeader(file))
{
cerr << "Cannot read header file";
return 0;
}
for(unsigned i=0; (i < this->dataSize); i++)
{
float c = (unsigned)(unsigned char)data[i];
this->rawData.push_back(c);
}
return true;
}
bool Wav::readwav(string theFile, ReadType type = DOUBLE)
{
// Attempt to open the .wav file
ifstream file (theFile.c_str());
cout << "This is the double information";
return true;
}
Because 'native' is a multi-char character, not a string. I'd go with multiple versions of the function though:
bool readwavNative(string theFile);
bool readwavDouble(string theFile);
or at least an enum as the second parameter:
enum ReadType
{
ReadNative,
ReadDouble
};
//...
bool readwav(string theFile, ReadType type);
Sounds like what you want is an enumeration with a default parameter.
enum FileType
{
NATIVE=0,
DOUBLE
};
bool readwav(string theFile, FileType type = NATIVE);
Default parameters are present in the function declaration, do not put them in the definition.
bool readwav(string theFile, FileType type)
{
switch(type)
{
case NATIVE: { ... } break;
case DOUBLE: { ... } break;
default: { ... } break;
}
}
This way, calling readwav without a parameter will use the NATIVE type by default.
readwav("myfile.wav"); // Uses NATIVE type
readwav("myfile.wav", NATIVE); // Also uses NATIVE
readwav("myfile.wav", DOUBLE); // Uses DOUBLE type
The question has oop in it so I would assume an oop answer is wanted. I think a strategy patter would suit your purpose.
class WavReader
{
public:
WavReader(const std::string fileName)
{
//open file and prepare to read
}
virtual ~WavReader()
{
//close file
}
virtual bool read()=0;
};
class NativeWavReader: public WavReader
{
public:
NativeWavReader(const std::string fileName): WavReader(fileName){}
virtual bool read()
{
//native reading method
std::cout<<"reading\n";
return true;
}
};
NativeWavReader implements the read method from the strategy WavReader, if you want another method you create a class OtherWavReader reading the file differently.
I'm writing an xml parser and I need to add objects to a class generically, switching on the actual type of the object. Problem is, I'd like to keep to an interface which is simply addElement(BaseClass*) then place the object correctly.
void E_TableType::addElement(Element *e)
{
QString label = e->getName();
if (label == "state") {
state = qobject_cast<E_TableEvent*>(e);
}
else if (label == "showPaytable") {
showPaytable = qobject_cast<E_VisibleType*>(e);
}
else if (label == "sessionTip") {
sessionTip = qobject_cast<E_SessionTip*>(e);
}
else if (label == "logoffmedia") {
logoffMedia = qobject_cast<E_UrlType*>(e);
}
else {
this->errorMessage(e);
}
}
This is the calling class, an object factory. myElement is an instance of E_TableType.
F_TableTypeFactory::F_TableTypeFactory()
{
this->myElement = myTable = 0;
}
void F_TableTypeFactory::start(QString qname)
{
this->myElement = myTable = new E_TableType(qname);
}
void F_TableTypeFactory::fill(const QString& string)
{
// don't fill complex types.
}
void F_TableTypeFactory::addChild(Element* child)
{
myTable->addElement(child);
}
Element* F_TableTypeFactory::finish()
{
return myElement;
}
void F_TableTypeFactory::addAttributes(const QXmlAttributes &attribs) {
QString tName = attribs.value(QString("id"));
myTable->setTableName(tName);
}
Have you considered using polymorphism here? If a common interface can be implemented by each of your concrete classes then all of this code goes away and things become simple and easy to change in the future. For example:
class Camera {
public:
virtual void Init() = 0;
virtual void TakeSnapshot() = 0;
}
class KodakCamera : Camera {
public:
void Init() { /* initialize a Kodak camera */ };
void TakeSnapshot() { std::cout << "Kodak snapshot"; }
}
class SonyCamera : Camera {
public:
void Init() { /* initialize a Sony camera */ };
void TakeSnapshot() { std::cout << "Sony snapshot"; }
}
So, let's assume we have a system which contains a hardware device, in this case, a camera. Each device requires different logic to take a picture, but the code has to support a system with any supported camera, so we don't want switch statements littered throughout our code. So, we have created an abstract class Camera.
Each concrete class (i.e., SonyCamera, KodakCamera) implementation will incluse different headers, link to different libraries, etc., but they all share a common interface; we just have to decide which one to create up front. So...
std::unique_ptr<Camera> InitCamera(CameraType type) {
std::unique_ptr<Camera> ret;
Camera *cam;
switch(type) {
case Kodak:
cam = new KodakCamera();
break;
case Sony:
cam = new SonyCamera();
break;
default:
// throw an error, whatever
return;
}
ret.reset(cam);
ret->Init();
return ret;
}
int main(...) {
// get system camera type
std::unique_ptr<Camera> cam = InitCamera(cameraType);
// now we can call cam->TakeSnapshot
// and know that the correct version will be called.
}
So now we have a concrete instance that implements Camera. We can call TakeSnapshot without checking for the correct type anywhere in code because it doesn't matter; we know the correct version for the correct hardware will be called. Hope this helped.
Per your comment below:
I've been trying to use polymorphism, but I think the elements differ too much. For example, E_SessionTip has an amount and status element where E_Url just has a url. I could unify this under a property system but then I lose all the nice typing entirely. If you know of a way this can work though, I'm open to suggestions.
I would propose passing the responsibility for writing the XML data to your types which share a common interface. For example, instead of something like this:
void WriteXml(Entity *entity) {
switch(/* type of entity */) {
// get data from entity depending
// on its type and format
}
// write data to XML
}
Do something like this:
class SomeEntity : EntityBase {
public:
void WriteToXml(XmlStream &stream) {
// write xml to the data stream.
// the entity knows how to do this,
// you don't have to worry about what data
// there is to be written from the outside
}
private:
// your internal data
}
void WriteXml(Entity *entity) {
XmlStream str = GetStream();
entity->WriteToXml(stream);
}
Does that work for you? I've done exactly this before and it worked for me. Let me know.
Double-dispatch may be of interest. The table (in your case) would call a virtual method of the base element, which in turns calls back into the table. This second call is made with the dynamic type of the object, so the appropriate overloaded method is found in the Table class.
#include <iostream>
class Table; //forward declare
class BaseElement
{
public:
virtual void addTo(Table* t);
};
class DerivedElement1 : public BaseElement
{
virtual void addTo(Table* t);
};
class DerivedElement2 : public BaseElement
{
virtual void addTo(Table* t);
};
class Table
{
public:
void addElement(BaseElement* e){ e->addTo(this); }
void addSpecific(DerivedElement1* e){ std::cout<<"D1"; }
void addSpecific(DerivedElement2* e){ std::cout<<"D2"; }
void addSpecific(BaseElement* e){ std::cout<<"B"; }
};
void BaseElement::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement1::addTo(Table* t){ t->addSpecific(this); }
void DerivedElement2::addTo(Table* t){ t->addSpecific(this); }
int main()
{
Table t;
DerivedElement1 d1;
DerivedElement2 d2;
BaseElement b;
t.addElement(&d1);
t.addElement(&d2);
t.addElement(&b);
}
output: D1D2B
Have a Look at the Visitor Pattern, it might help you