I'm new to C++ , although have programmed Arduinos using C before and have been programming Windows apps for 30 odd years. So I understand concepts like virtual methods and overridng them but I'm struggling to get an overridden virtual method in a derived class called by the constructor.
Here's the code
class VelbusNode
{
public:
VelbusNode();
virtual void init();
protected: // some data members
byte nodeType = 0x05; // use this value unless changed
byte mapVersion;
};
class VelbusNode_VMBGPO: public VelbusNode
{
public:
VelbusNode_VMBGPO();
virtual void init() override;
};
The implementation of the base class looks like this
VelbusNode_VMBGPO::VelbusNode_VMBGPO()
: VelbusNode::VelbusNode()
{}
void VelbusNode_VMBGPO::init()
{
VelbusNode::init(); // call the base class version first
nodeType = 0x21; // now override the values
}
and finally the code is used like this
VelbusNode_VMBGPO* node;
node = new VelbusNode_VMBGPO();
When I inspect the value assigned the node->nodeType it is the value set in the initial declaration i.e. 0x05. mapVersion is 1 as expected because the base init code has been called.
Given that the declaration and call to the constructor is for the derived class (VelbusNode_VMBGPO) I'd be expecting to see the base constructor call the overridden init function. But it appears to only call its own function, which makes the concept of polymorphism a bit broken.
What do I need to change so that the constructor for the instance of the derived class calls the correct code ?
you would get better and faster answers if you would provide a full working example.
You could call the init in the constructor of the derived class.
class VelbusNode {
public:
VelbusNode();
virtual void init();
byte getNodeType() {
return nodeType;
}
protected: // some data members
byte nodeType = 0x05; // use this value unless changed
byte mapVersion;
};
class VelbusNode_VMBGPO: public VelbusNode {
public:
VelbusNode_VMBGPO();
virtual void init() override;
};
VelbusNode::VelbusNode() {
init();
}
void VelbusNode::init() {
mapVersion = 1;
}
VelbusNode_VMBGPO::VelbusNode_VMBGPO()
: VelbusNode::VelbusNode()
{init();} // !
void VelbusNode_VMBGPO::init() {
VelbusNode::init(); // call the base class version first
nodeType = 0x21; // now override the values
}
void setup() {
Serial.begin(115200);
VelbusNode_VMBGPO* node;
node = new VelbusNode_VMBGPO();
Serial.println(node->getNodeType(), HEX);
}
void loop() {
// put your main code here, to run repeatedly:
}
Thanks for the reply. I've just stumbled upon this but it seems to be counter intuitive.
I think it is because from what I've read C++ constructors are not virtual so they do not act in a polymorphic way, unlike normal functions. Which is not how my experience outside of C++ works.
So, a bit of a learning curve and trying not to trip myself up by assuming similar paradigms as other languages.
That's a known problem with C++ constructors. Many classes have a begin() method that does the intended initialization after and outside the constructor.
Thanks for the tip.
As a Delphi/Pascal and C# developer it is a different paradigm for me, but figuring out that programming "mental" model is about 50% of the task.
I'll look at using that rather than relying on the constructor to call it.