Eraser wrote:Doesn't overriding non-virtual methods throw a compiler error in C++? I think the Visual Studio C# compiler does.
Nope.
virtual methods in C++ are overridden through the use of virtual tables which are just pointers to the most-derived available function in the inheritance tree.
For instance:
Code: Select all
class animal{
public:
virtual ~animal(){}
virtual void function_one(){ std::cout << "generic animal sound one" << std::endl; }
void function_two(){ std::cout << "generic animal sound two" << std::endl; }
virtual void table_example(){ /* I do nothing */ }
};
class cat: public animal{
public:
~cat(){}
virtual void function_one(){ std::cout << "meow" << std::endl; }
void function_two(){ std::cout << "purrrrr" << std::endl; }
virtual void table_example(){ /* I also do nothing*/ }
};
class dog : public animal{
public:
~dog(){}
virtual void function_one(){ std::cout << "woof" << std::endl; }
void function_two(){ std::cout << "grrrrrrrrrrrrrr" << std::endl; }
};
There is a virtual table made for animal, cat, and dog.
The table for animal looks like:
function_pointer* a_function = &(animal::function_one);
function_pointer* b_function = &(animal::table_example);
The table for cat looks like:
function_pointer* a_function = &(cat::function_one);
function_pointer* b_function = &(cat::table_example);
And the table for dog looks like:
function_pointer* a_function = &(dog::function_one);
function_pointer* b_function = &(animal::table_example);
NOTE that because dog doesn't have a function overriding table_example() that the most-derived function available for dog is animal::table_example() yet, in the case of cat, which does provide its own version of the function, the most-derived is cat::table_example().
------------------------------------------------------------
Now if you were to create an instance of one of these classes such as:
Code: Select all
animal *kitty = new cat();
kitty->function_one(); //calling cat::function_one();
kitty->function_two(); //calling animal::function_two();
delete kitty;
animal *montgomery = new dog();
montgomery->function_one(); //calling dog::function_one();
montgomery->function_two(); //calling animal::function_two();
delete montgomery;
You'd get the following output:
- meow
generic animal sound two
woof
generic animal sound two
Note that here the base type of the object we're calling the functions for is
animal so the functions being called look like this (based off the vtable):
cat::function_one() //this IS overridden as there's an entry in cat's vtable (it's a virtual function)
animal::function_two() //this is NOT overridden since there's no entry in cat's vtable for this (it's not a virtual function)
dog::function_one()
animal::function_two()
If you created a new instance of a creature such as:
Code: Select all
cat *kitty = new cat();
kitty->function_one();
kitty->function_two();
delete kitty;
Then the output would be:
meow
purrrrrr
In THIS example the objects base class is cat rather than animal. Now the functions being called look like:
cat::function_one();
cat::function_two();
-----------------------------------------
I guess, in a nutshell, an error isn't thrown because non-virtual methods don't override the inherited methods. The purpose of the virtual keyword is to say, with our example in mind, "If the function in animal also exists in the derived class, use the derived class's version." (this is function_one). Otherwise, without the virtual keyword the compiler simply uses animal's version of the function if that's the base type of the pointer used to instantiate the creature be it cat or dog. (this is function_two)