Sunny Lei
Sunny Lei

Reputation: 181

Overriding method in C++

I am trying to override function add() in the inherited class NumericInput. But when I call add() on a NumericInput object the add() function in the base class is called. Why is this?

#include <iostream>
#include <string>

class TextInput
{
public:
    std::string cur;
    void add(char c) 
   {
        cur += c;
        std::cout<<"input is: "<<c<<'\n';
   }

   std::string getValue() {return cur;}
};

class NumericInput : public TextInput 
{
   public:
   void add(char c) 
   {
    if(c>=48 && c <= 57)
    {
        std::cout<<"input is a digit: "<< c <<'\n';
        cur += c;
    }
    else
    {
        std::cout<<"input is not digit"<<'\n';}
    }
};

int main()
{
    TextInput* input = new NumericInput();
    input->add('1');
    input->add('a');
    input->add('0');
    std::cout << input->getValue();
}

Upvotes: 1

Views: 976

Answers (2)

Vlad Tamas
Vlad Tamas

Reputation: 33

I would suggest using :

bool my_isdigit(char ch)
{
    return std::isdigit(static_cast<unsigned char>(ch));
}

in order to verify that your char is digit or not

Upvotes: 0

Henri Menke
Henri Menke

Reputation: 10939

As said in the comment, make it virtual. It is also good practice to mark the overriding function with override. That way you will get a compiler error when there is no function to override (usually because of a typo in the name).

Also any class with virtual functions should have a virtual destructor so that it can be deleted via a pointer. Don't forget to to delete the pointer as well!

#include <iostream>
#include <string>

class TextInput
{
public:
    std::string cur;

    virtual ~TextInput() = default;

    virtual void add(char c)
    {
        cur += c;
        std::cout<<"input is: "<<c<<'\n';
    }

    std::string getValue() {return cur;}
};

class NumericInput : public TextInput 
{
public:
    virtual void add(char c) override
    {
        if(c>=48 && c <= 57)
        {
            std::cout<<"input is a digit: "<< c <<'\n';
            cur += c;
        }
        else
        {std::cout<<"input is not digit"<<'\n';}
    }
};

#ifndef RunTests
int main()
{
    TextInput* input = new NumericInput();
    input->add('1');
    input->add('a');
    input->add('0');
    std::cout << input->getValue() << '\n';
    delete input;
}
#endif

This is also a good place to apply the non-virtual interface idiom. The base class has a member function add which is not virtual and takes care of add the character to the string cur. It does so if do_add reports that the character should be added. The function do_add is virtual and, most importantly, private. This ensures encapsulation and makes the class portable. See Item 35 “Consider alternatives to virtual functions” in Effective C++ by Scott Meyers.

Also, use a std::unique_ptr to manage the memory of your class.

#include <iostream>
#include <string>
#include <memory>

class TextInput
{
    std::string cur;

    virtual bool do_add(char c)
    {
        std::cout<<"input is: "<<c<<'\n';
        return true;
    }

public:
    virtual ~TextInput() = default;

    void add(char c)
    {
        if ( do_add(c) )
            cur += c;
    }

    std::string getValue()
    {
        return cur;
    }
};

class NumericInput : public TextInput 
{
    virtual bool do_add(char c) override
    {
        if ( c>=48 && c <= 57 )
        {
            std::cout<<"input is a digit: "<< c <<'\n';
            return true;
        }

        std::cout<<"input is not digit"<<'\n';
        return false;
    }
};

#ifndef RunTests
int main()
{
    auto input = std::unique_ptr<TextInput>{new NumericInput()};
    input->add('1');
    input->add('a');
    input->add('0');
    std::cout << input->getValue() << '\n';
}
#endif

Upvotes: 1

Related Questions