7

I have a class that contains some functions (none are virtual) and 2 more classes publicly inherit that class. In both the sub classes I override the same function of the base class.

After creating objects of all three classes in main (located at the same file), I call the original function with the baseclass object and the overridden functions with the derivedclass objects.

I was expecting all 3 function calls to run the original function from the base class (since I didn't use 'virtual' anywhere in the code), but I actually get each version of that function working according to the class in which it was defined (3 different versions).

I have the classes Base & Derived as follows:

struct Base
{
   void foo();
};

struct Derived : Base
{
   void foo();
};

in main:

int main()
{
   Derived d;
   d.foo();
}

I thought d.foo() should run Base::foo() if not using 'virtual'.

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
theexplorer
  • 359
  • 1
  • 5
  • 21

3 Answers3

26

This is not "overriding"... and it doesn't need to be.

struct Base
{
   void foo();
};

struct Derived : Base
{
   void foo();
};

int main()
{
   Derived d;
   d.foo();
}

If I understand you correctly, then you were expecting this to execute Base::foo(), because the functions are not virtual and therefore one does not override the other.

But, here, you do not need virtual dispatch: the rules of inheritance simply state that you'll get the right function for the type of the object you run it on.

When you need virtual dispatch/overriding is a slightly different case: it's when you use indirection:

int main()
{
   Base* ptr = new Derived();
   ptr->foo();
   delete ptr;
}

In the above snippet, the result will be that Base::foo() is called, because the expression ptr->foo() doesn't know that *ptr is really a Derived. All it knows is that ptr is a Base*.

This is where adding virtual (and, in doing so, making the one function override the other) makes magic happen.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 2
    Is your derived supposed to be deriving from base? – Brandon Jan 12 '14 at 16:36
  • @Lightness Races in Orbit: I do have a question about this too :) I hope it's ok: when creating an array of Base objects like this: `Base array[2]={derivedObj1, derivedObj2};` **array[0].foo();** runs the Base's foo() and not the Derived's foo() even if it is 'virtual' at the Base class. on the other hand, when creating an array of Base objects like this: `Base *array[2]={new Derived(), new Derived()};` **array[0].foo();** runs the Derived's foo()... can I get the first option to work polymorphic like the second one? – theexplorer Jan 12 '14 at 17:19
  • @theexplorer: No, [you're _slicing_ your objects](http://stackoverflow.com/q/274626/560648). They are actually copied into `Base` objects for storage. – Lightness Races in Orbit Jan 12 '14 at 17:20
  • @Lightness Races in Orbit: ok, I understand. thank you. – theexplorer Jan 12 '14 at 17:27
2

You cannot override something that isn't virtual. Non-virtual member functions are dispatched statically based on the type of the instance object.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • How is that so? Method overriding, in object-oriented programming, is a language feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its superclasses or parent classes. The version of a method that is executed will be determined by the object that is used to invoke it. That's literally what I get when I don't use the key-word "virtual" – Heil Programmierung Dec 08 '22 at 14:47
0

You could cheat by "overriding" a function by making it an inline function calling something indirectly. Something like (in C++03)

 class Foo;
 typedef int foo_sig_t (Foo&, std::string&);
 class Foo {
    foo_sig_t *funptr;
 public:
    int do_fun(std::string&s) { return funptr(*this,s); }
    Foo (foo_sig_t* fun): funptr(fun) {};
    ~Foo () { funptr= NULL; };
    // etc
 };

 class Bar : public Foo {
    static int barfun(Bar&, std::string& s) { 
       std::cout << s << std::endl;
       return (int) s.size();
    };
  public: 
    Bar () : Foo(reinterpret_cast<foo_sig_t*>)(&barfun)) {};
     // etc...
  };

and later:

  Bar b;
  int x=b.do_fun("hello");

Officially this is not overloading a virtual function, but it looks very close to one. However, in my above Foo example each Foo instance has its own funptr, which is not necessarily shared by a class. But all Bar instances share the same funptr pointing to the same barfun.

BTW, using C++11 lambda anonymous functions (internally implemented as closures), that would be simpler and shorter.

Of course, virtual functions are in generally in fact implemented by a similar mechanism: objects (with some virtual stuff) implicitly start with a hidden field (perhaps "named" _vptr) giving the vtable (or virtual method table).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547