-
Notifications
You must be signed in to change notification settings - Fork 839
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Polymorphism and class inheritance #634
Comments
@glmnet To be very clear: I strongly suggest not to propagate polymorphism in new code. Personally, I am happy that this repo has stayed away from it. |
Ok, thanks for the explanation. I suspect some of that might be an issue. |
@devyte so is this vtable using memory only when objects are instantiated? (I'm not a C++ expert, more C# guy here) but in any case one should create an specific instance of an AC type only when needed, and then discard it, this should use heap memory that should be freed as soon as code is sent.
Am I missing something here? Could you elaborate on a better approach to this problem? |
Yes, and that illustrates the case even more so. Polymorphism is appropriate when you have a bunch of different objects, have instances of them, and you need to treat all instances in a similar way. Classic example: 3D shapes where each shape knows how to render itself. You build a container with polygons, rectangles, squares, circles, whatever, and then you treat them all the same for transformations, drawing, etc. Taking your own code snippet: consider a template object that implements common behavior, let's call it BaseAC, and specific classes that implement individual things specific to each case, let's call those CoolixAc, WhirlpoolAc, etc. You could then do something like this: switch (acModel) {
case 'Coolix':
sendAc<CoolixAc>(onOffState, modeCoolHeat, temp, fanSpeed);
break;
case 'Whirlpool':
sendAc<WhirlpoolAc>(onOffState, modeCoolHeat, temp, fanSpeed);
break;
}
template <typename AcType>
void sendAc(bool onOffState, tempMode modeCoolHeat, int temp, int fanSpeed) //instead of specific args you could have a template pack in generic manner, and forward that pack to the ac constructor. This allows to have different Ac objects with completely different arguments.
{
BaseAc<AcType> AC(onOffState, modeCoolHeat, temp, fanSpeed);
AC.send();
}
struct CoolixAc
{
CoolixAc(bool onOffState, tempMode modeCoolHeat, int temp, int fanSpeed);
....
std::vector<uint8_t> buildSendCommand();
setupIRParams getIRSetup() {return setupIRParams(someparamshere);}
//data members here, onOffState, tempMode, whatever
};
class WhirlpoolAc
{
WhirlpoolAc(bool onOffState, tempMode modeCoolHeat, int temp, int fanSpeed);
....
std::vector<uint8_t> buildSendCommand();
setupIRParams getIRSetup() {return setupIRParams(someotherparamshere);}
//data members here, onOffState, tempMode, whatever
};
template <typename AcType>
class BaseAc
{
public:
BaseAc(bool onOffState, tempMode modeCoolHeat, int temp, int fanSpeed)
: ac(onOffState, tempMode, modeCoolHeat, temp, fanSpeed);
void send()
{
//somecommonlogicthatmakesuseoftheacmemberobject...
auto params = _ac.getIRSetup();
doIRSetup(params);
auto command = _ac.buildSendCommand();
doSendCommand(command);
}
protected:
AcType _ac;
}; Or you could do this, which is simpler on the template side, but can have more duplicity in the instantiation side: switch (acModel) {
case 'Coolix':
BaseAc<CoolixAc> ac(onOffState, modeCoolHeat, temp, fanSpeed);
ac.send();
break;
case 'Whirlpool':
BaseAc<WhirlpoolAc> ac(onOffState, modeCoolHeat, temp, fanSpeed);
ac.send();
break;
}
struct CoolixAc
{
CoolixAc(bool onOffState, tempMode modeCoolHeat, int temp, int fanSpeed);
....
std::vector<uint8_t> buildSendCommand();
setupIRParams getIRSetup() {return setupIRParams(someparamshere);}
//data members here, onOffState, tempMode, whatever
};
struct WhirlpoolAc
{
WhirlpoolAc(bool onOffState, tempMode modeCoolHeat, int temp, int fanSpeed);
....
std::vector<uint8_t> buildSendCommand();
setupIRParams getIRSetup() {return setupIRParams(someotherparamshere);}
//data members here, onOffState, tempMode, whatever
};
template <typename AcType>
class BaseAc
{
public:
BaseAc(bool onOffState, tempMode modeCoolHeat, int temp, int fanSpeed)
: ac(onOffState, tempMode, modeCoolHeat, temp, fanSpeed);
void send()
{
//somecommonlogicthatmakesuseoftheacmemberobject...
auto params = _ac.getIRSetup();
doIRSetup(params);
auto command = _ac.buildSendCommand();
doSendCommand(command);
}
protected:
AcType _ac;
}; The BaseAc object would implement common logic, e.g. (I'm guessing here, I don't know how the code in the repo works yet):
I used std::vector<uint8_t> for the command sequence, but it could be something else, like std::array, or even a smart pointer with a C-style array. Disclaimer: the above is off the very top of my head, and is meant as a very general example on template usage. I don't know how well it applies to the specifics of the usage of the code here, given that I'm not a user of this code yet. There could be other approaches to the template object design. However, I think it should illustrate one possibility for template use. |
Ok thanks for all the information.
|
I have intermittently working OpenHAB code for option one that you’re welcome to, albeit for sending the Daikin2 protocol via IRMQTTServer. Doing further work shortly today to try and work out why it’s intermittent and I won’t be able to post it until later tonight or tomorrow (GMT + 13) |
@devyte Wow. I had no idea how expensive it was, but I did figure it had some cost. When I develop a solution for a more universal model for handling A/Cs I'll definitely re-look up this issue. Thanks for the awesome detail/response btw. I look forward to your future feedback/input if/when you use the library. ;-) |
I am very interested to your solution on this. I use .map files of this short.
|
My code is a whole lot more complicated as I construct the full hex string from scratch using a combination of fixed variables, user settings, the current time and also calculate a checksum. My code will likely create more questions than answers. In your case I’d just use a simple rule to build a string and then send that using a publish command. I’ll see if I can knock something together tomorrow to give you a clue, although this may be better posted in the OpenHAB community? |
I can't test this, but it should work. I'm assuming you have a string item called "HeatpumpSetting" which is whatever mode you want it to select. I've also left in a couple of log statements which can be commented out once you know its working. It uses V1 versions of the MQTT binding and MQTT Actions `
` |
Hi, I see many classes which are AC related they have methods like void setTemp(const uint8_t temp);
However they are all plain classes which do not inherit from anything
Is there any reason why there is no BaseAC which some virtual methods for setTemp and other common methods to all ac?
I guess code from like the MQTTServer would beneficiate from this if instead of receiving a raw code (which has to be magically calculated outside the library) could instead receive the AC settings (temp, fan speed, etc) and then use this class + polymorphism to calculate the code (a feature already implemented)
The text was updated successfully, but these errors were encountered: