What is a "virtual" declaration?

I am trying to modify an existing LeftCoast library to add a method. I am in way over my head to create a a library, but I have to start somewhere.

There a declaration that I can't find any reference to. What does virtual do?
Here's the whole .h file:

#ifndef timeObj_h        //This prevents problems if someone accidently #include's your library twice.
#define timeObj_h

// Insanely handy for doing things in the background.
// Set the timer and wait 'till it goes "ding". 
// Great for blinking LEDs, updating readings, etc.
// May not fast & accurate enough for RC Servos.
// *** Takes care of roll over issues ***
//
// NOTE: Once the timer expires, every call to ding() will return true until its been
// restarted.


class timeObj {                                     //Create a class

  public:                                           //functions you can call from another program
    //constructor- which is used to create an instance of the class.
    timeObj(float inMs=10,bool startNow=true); //startNow defaults to true
 
    virtual ~timeObj(void);
    void setTime(float inMs,bool startNow=true);    // Change the time duration for next start..
    virtual void start(void);                       // Start the timer "now".
    void stop(void);                                // Stop the timer so that ding() will always be false.
    virtual void stepTime(void);                    // Restart the timer from last end time.
    bool ding(void);                                // Timer has expired.
    unsigned long getTime(void);                    // How long does this go for?
    float getFraction(void);                        // Fuel gauge. What fraction of time is left.
    void printState(void);                          // Debugging.
          
  private:
    enum timeObjStates  { preStart, running, expired, stopped };
        
    bool useMilli;
    timeObjStates ourState;
    unsigned long waitTime;
    unsigned long startTime;
    unsigned long endTime;
};

#endif

What does "virtual" do here?

A virtual function is a member function which is declared within a base class and overriden by a derived class.

...and does not, and can not have, any implementation in the base class... IIRC

aarg:
...and does not, and can not have, any implementation in the base class... IIRC

Actually, it can. In which case a derived class can override it, ...... or not.

However, if the declaration is on the order of:

virtual void stepTime(void) = 0;

then, the class is purely virtual (aka abstract). Then no objects of the class may be instantiated. Some derived class must implement the function in order for objects to be instantiated.

For example, from Print.h:

virtual size_t write(uint8_t) = 0;

No Print objects can be instantiated. Stream derives from Print, but does not implement write(). So, no Stream objects can be instantiated. But, HardwareSerial derives from Stream and does implement write(). 'Serial' (as in Serial.print) is an instantiated object of the HardwareSerial class.

IDRC :frowning: ... but can't you override a method in a base class, without 'virtual'?

Yea, but I think there's some subtle difference. Something like if you override a non-virtual method then NONE of the base class's methods are available in the derived class. But, I'm at the edge of my knowledge here, so don't take that to the bank.

Virtual functions required to achieve run time polymorphism. So you can use base type class pointer to works with code defined at derived class.
https://www.programiz.com/cpp-programming/virtual-functions

What are you trying to add?

Oh, your stop() method. I already added reset() for you and it does exactly what you wanted.

-jim lee ← Left Coast

jimLee:
What are you trying to add?

Oh, your stop() method. I already added reset() for you and it does exactly what you wanted.

-jim lee ← Left Coast

Thanks, Jim. I realized that you added the reset method when I went back to github to close the issue I started, (and after I added the stop method)… I downloaded your latest.
But, I am still trying to learn about writing libraries, so that’s why the question. I had never seen ‘virtual’ before.

TheMemberFormerlyKnownAsAWOL:
A virtual function is a member function which is declared within a base class and overriden by a derived class.

You lost me at base class, then whacked me with derived class. (The more I learn, the dumber I feel).

In the example library that I am studying there is only one class, so what does 'virtual' do in this case?

SteveMann:
In the example library that I am studying there is only one class, so what does 'virtual' do in this case?

I haven't look at the source code in question. But, the author may do that so that you can create your own derived classes based on the existing ones.

The deal with a base class is you can set the structure of how things interact. A perfect example is something like ..

// base class

class rect {

public:
rect(int x,int y,int width,int height); // Constructor
~rect(void); // Destructor

bool inRect(int x,int y); // Is this x,y point in this rect

int x;
int y;
int width;
int height;
};

// Derived class drawObj

class drawObj : public rect {

public:
drawObj(int x,int y,int width,int height); // Constructor
~drawObj(void); // Destructor

virtual drawSelf(void);
};

Basically the derived class is just adding things to the base class. Every drawObj will have the inherited ability to determine if an x,y point lies inside of itself because its base class rect has that method.

Notice the virtual drawSelf() method? Different things that go on your display will need to draw themselves differently. The virtual lets you "override" the default drawing method with the drawing you actually want.

Something like a label class would add data and methods about fonts text sizes, what the text actually is etc. Since we assume the drawObj knows how to draw itself to the screen and also when x,y points lie within it.. You get all this fun stuff in the package.

Its like adding layers.

In my stuff I have a base class called idler. It has one virtual method

virtual void idle(void);

The purpose of this class is for you to inherit it, and create your own class that runs in the background. What does it do in the background? Whatever you write in your derived idle(); method. How does it actually run in the background? Magic? Its all taken care of for you by the interaction of the base classes you don't need to deal with.

Talk about many things at a time. idler lets you have hundreds of things running at the same time and it sorts them all out for you and runs them. This is how I did my smartPhone. 95% of it is just little idlers doing little tasks in the background.

Base classes typically set up the framework and interaction for your derive custom classes.

Hope this helps?

-jim lee

Typically, the most general class is the ‘Base’ class and derived classes are more specific. Here is an example where the base class is “Drawable”, a graphic object made up of lines. This way, an object made of lines doesn’t have to contain its own line drawing function.

The first derived class is “Rectangle”. It must have a ‘draw()’ function since it “is derived from”/“is a type of” Drawable. It uses the ‘line()’ method of the base class to draw its four sides.

Then a Square class is derived from the Rectangle class. The only difference is that the constructor only needs three arguments.

class Drawable
{

  public:
    Drawable(void) {}; // Constructor
    ~Drawable(void) {};   // Destructor

    void line(int x1, int y1, int x2, int y2)
    {
      Serial.print("line(");
      Serial.print(x1);
      Serial.print(", ");
      Serial.print(x2);
      Serial.print(", ");
      Serial.print(y1);
      Serial.print(", ");
      Serial.print(y2);
      Serial.println(");");
    }

    virtual void draw(void) = 0;
};

class Rectangle : public Drawable
{

  public:
    Rectangle(int x, int y, int width, int height) : x(x), y(y), width(width), height(height)
    {
    }
    ~Rectangle(void) {};   // Destructor

    void draw(void)
    {
      line(x, y, x + width, y); // Top
      line(x, y, x, y + height); // Left
      line(x, y + height, x + width, y + height); // Bottom
      line(x + width, y, x + width, y + height); // Right
    }

    bool   inside(int x1, int y1) // Is this x,y point in this rect
    {
      return (x1 >= x && x1 <= (x + width) && y1 >= y && y1 <= (y + height));
    }

    int x;
    int y;
    int width;
    int height;
};


class Square : public Rectangle
{
  public:
    Square(int x, int y, int size) : Rectangle(x, y, size, size) {}
};

void setup()
{
  Serial.begin(115200);
  Square s(10, 20, 30);
  s.draw();
  Serial.println(s.inside(15, 25) ? "True" : "False");
}

void loop() {}

Output:

line(10, 40, 20, 20);
line(10, 10, 20, 50);
line(10, 40, 50, 50);
line(40, 40, 20, 50);
True

I’m sorry John but, at least to me, that is totally confusing! I can not make heads or tails of what you are trying to say there.

-jim lee

SteveMann:
You lost me at base class, then whacked me with derived class. (The more I learn, the dumber I feel).

In the example library that I am studying there is only one class, so what does 'virtual' do in this case?

Base class, derived class and virtual functions are all features that C++ offers you, so it's easy to find extensive tutorials that explain them.

It looks like you unfortunately picked a library to experiment with that's encouraging polymorphism. If your primary aim is to learn about building libraries, I'd suggest that you find another simpler one to add methods to. You can always come back to this one when you're comfortable with the base class simplest case :slight_smile:

Geeky anecdote:
One day I was discussing Indian bread names with an Indian colleague and wanted to know what the word for bread is in Hindi. "It depends. There's naan, paratha, poori, chapati and many others".
"No no no, what's the generic word for bread - the base class?"
"Oh I see, roti."

jimLee:
I’m sorry John but, at least to me, that is totally confusing! I can not make heads or tails of what you are trying to say there. -jim lee

I’m sorry that you found my sketch confusing. I hope someone else will find it helpful in the understanding of base and derived classes.

johnwasser:
I'm sorry that you found my sketch confusing. I hope someone else will find it helpful in the understanding of base and derived classes.

Actually, after reading your code, I think I got a spark of understanding inheritance, but my question was about 'virtual'.

But the Indian word for bread was good a good analogy as well.

SteveMann:
I think I got a spark of understanding inheritance, but my question was about 'virtual'.

The relationship between inheritance and the 'virtual' specification was covered in Reply #'s 1, 3, and 5.

johnwasser:
I hope someone else will find it helpful in the understanding of base and derived classes.

Yes, it's a classic example of inheritance going from General to Specific.
@jimLee's example application of the concept was backwards from that.

@gfvalvo I.. I think your totally missing what I was saying.

"No no no, what's the generic word for bread - the base class?"
"Oh I see, roti."

I was saying the exact same thing as wildBill was saying with the bread thing.

What does everything you draw on a screen have in common? A location, width and height. So your base class can have all that rectangle math in it for everything you draw on a screen. Buttons, lines, text and pictures are all in effect.. rectangles.

An example would be clicking something on a screen. Say is a complicsted shape. And there a bunch of different things on the screen as well.

Go through and ask all the rectangles if the x,y touch happened in them.

If the shape is still a rectangle, like an icon. It can ignore the call because its base rectangle class will do a fine job dealing with it.

If the shape is a circle? It can inherit the bool pointInMe(x,y) method and do a better job seeing if the point lands within the circle. In fact, if it wants, it can ask the base rectanlge it is rect:: pointInMe(x,y) and if it returns false, return false and skip the math.

General [rect] -->> more Specific [circle, icon, line..]

The framework for stuff is laid out using the General [lists of rectangles] and what the user interacts with is the more Specific [circles, icons, lines..] stuff she sees on the screen.

This all just sounds like gibberish doesn't it?

-jim lee