Adam Haile
Adam Haile

Reputation: 31359

Overriden Virtual methods not being called

I'm trying to create an abstract class that some other classes can be based off of for an arduino project. But, whenever I call a method that is virtual in the base, it just calls the base implementation. Code below. Can anyone see what I'm doing wrong?

#define RTCBASE 0
class RTC_Base {
public:
  virtual uint8_t begin(void){ return 0; };
  virtual void adjust(const DateTime& dt){};
  virtual DateTime now(){ return DateTime(); };
  virtual int Type(){ return RTCBASE; };
};
////////////////////////////////////////////////////////////////////////////////
// RTC based on the DS1307 chip connected via I2C and the Wire library
#define DS1307 1
class RTC_DS1307 : public RTC_Base 
{
public:
  virtual int Type(){ 
    return DS1307; 
  }
  uint8_t begin(void);
  void adjust(const DateTime& dt);
  uint8_t isrunning(void);
  DateTime now();
  uint8_t readMemory(uint8_t offset, uint8_t* data, uint8_t length);
  uint8_t writeMemory(uint8_t offset, uint8_t* data, uint8_t length);


};

///In Code
RTC_Base RTC = RTC_DS1307();
DateTime dt = RTC.now();
//The above call just returns a blank DateTime();

Upvotes: 0

Views: 2499

Answers (1)

Jamin Grey
Jamin Grey

Reputation: 10495

You have the code:

RTC_Base RTC = RTC_DS1307();
DateTime dt = RTC.now(); //The above call just returns a blank DateTime();

That's object slicing (as @chris originally guessed). For Polymorphism to work, you'll have to pretend your derived class is a base class, by treating a pointer or reference as a Base, when it really is the address of a Derived. (Because the Derived actually contains the Base within it).

Derived myDerived;
Base &myBaseRef = myDerived;

myBaseRef.myVirtualFunction();

Otherwise, you are creating a Derived, and trying to force the bytes into a Base, and losing all the Derived's bytes. It's not good! =)

The point is, you shouldn't actually be converting the Derived to a Base, just accessing the Derived as if it were a Base. If you convert it to a Base, it is a base. And your Base class returns an empty DateTime.

To do so with dynamically allocated memory, you can do this:

Base *myBase = nullptr; //Or 'NULL' if you aren't using C++11
myBase = new Derived;

myBase->myVirtualFunction(); //Dereference the myBase pointer and call the function.

delete myBase; //Free the memory when you are finished.

If you are using C++11, you can let std::unique_ptr handle the lifetime of the object for you, so you don't have to remember to call 'delete':

std::unique_ptr<Base> myBase;

//Later...
myBase = new Derived;
myBase->myVirtualFunction();

//Automatically freed when the myBase smart pointer goes out of scope...

Upvotes: 2

Related Questions