Sign in to follow this  

[.net] what's the purpose of virtual keyword again?

This topic is 4205 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

okay, i've been programming for several years now with OO concepts. but im learning C#, and although it seems like a breeze (just like Java plus C++), i seem to be back-sliding and asking fundamental questions. like virtual functions. why do we need to explicity declare a function as virtual (or a deriving class function as override)? the answer, i know, is so we can use polymorphism and ultimately invoke the derive class' methods over the base class'. BUT...the statement directly above can be made possible without the use of the virtual/override keywords, no? what the heck am i missing here?! argh!

Share this post


Link to post
Share on other sites
http://www.jaggersoft.com/pubs/AProgrammersOverviewOfCSharp.htm#inheritance
http://www.extremetech.com/article2/0,1697,1164819,00.asp

edit: to be more helpful.

virtual in C#, just like C++, allows the program at runtime to pick the right reference or method at runtime. you would use the virtual keyword on the function of the base class. afterward use override on the function of the derived class. now "sealed override" not that experienced to fully understand that yet.

Share this post


Link to post
Share on other sites
Quoting Alpha's link:

Quote:
Unlike Java (and like C++) by default C# methods, indexers, properties, and events are not virtual.


If you redefine a non-virtual method in a derived class, you are hiding the base's, not overriding it, meaning that the method will be selected based on the static type of the variable, not its dynamic type.

Share this post


Link to post
Share on other sites
Your base class's function should have the keyword virtual and the derived class's implementation of that function should have the keyword override.


class SomeBaseClass
{
public virtual void Foo()
{
System.Console.WriteLine("Called SomeBaseClass's Foo!");
}
}

class SomeDerivedClass : SomeBaseClass
{
public override void Foo()
{
System.Console.WriteLine("Called SomeDerivedClass's Foo!");
}
}

Share this post


Link to post
Share on other sites
It's an detail to determine how the compiler implements that function call. It's basically an extra pointer indirection. But to make a short story long, here's an example:

// C++ with no virtual
#include <iostream>

class base {
protected:
int value;
public:
void print() const {
std::cout << "base: " << value << std::endl;
}

base(int v) :
value(v)
{}
};
class child : public base {
public:
void print() const {
std::cout << "child: " << value << std::endl;
}

child(int v) :
base(v)
{}
};

int main() {
base b(1);
child c(2);
base &ref_c = c;

b.print();
c.print();
ref_c.print();

/* Output:
* base 1
* child 2
* base 2
*/

}






// C++ with virtual
#include <iostream>

class base {
protected:
int value;
public:
virtual void print() const {
std::cout << "base: " << value << std::endl;
}

base(int v) :
value(v)
{}
};
class child : public base {
public:
virtual void print() const {
std::cout << "child: " << value << std::endl;
}

child(int v) :
base(v)
{}
};

int main() {
base b(1);
child c(2);
base &ref_c = c;

b.print();
c.print();
ref_c.print();

/* Output:
* base 1
* child 2
* child 2
*/

}





Okay you know how that all works already. Now to show you why they differ by going lower-level which I'm going to do in C because I can. Well, actually, because it seems more apt as you have no built-in virtual to rely upon. When you do not use virtual, it ends up being kind-of, sort-of implemented like this:

/* C with no virtual */
#include <stdio.h>

struct base {
int value;
};

void base_ctor(struct base *t, int v) {
t->value = v;
}

void base_print(const struct base *t) {
printf("base: %d\n", t->value);
}

struct child {
struct base parent;
};

void child_ctor(struct child *t, int v) {
base_ctor(&t->parent, v);
}

void child_print(const struct child *t) {
printf("child: %d\n", t->parent.value);
}

int main() {
struct base b;
struct child c;
struct base *ref_c = &c.parent;

base_ctor(&b, 1);
child_ctor(&c, 2);

base_print(&b);
child_print(&c);
base_print(ref_c);

/* Output:
* base 1
* child 2
* base 2
*/

}





Relatively simple. So, let's make it weird by pretending we're a C++ compiler in C:

/* C with virtual */
#include <stdio.h>

/* base */
void base_print_impl(const void *);

struct base_vtable_type {
void (*print)(const void *);
} base_vtable_impl = {
&base_print_impl
};

struct base {
struct base_vtable_type *vtable;
int value;
};

void base_print_impl(const void *t_void) {
struct base *t = (struct base *) t_void;

printf("base: %d\n", t->value);
}

void base_ctor_base(struct base *t, int v) {
t->value = v;
}
void base_ctor(struct base *t, int v) {
t->vtable = &base_vtable_impl;
base_ctor_base(t, v);
}

void base_print(struct base *t) {
(*t->vtable->print)(t);
}

/* child */
void child_print_impl(const void *);

struct base_vtable_type child_vtable_impl = {
&child_print_impl
};

struct child {
struct base parent;
};

void child_print_impl(const void *t_void) {
struct child *t = (struct child *) t_void;

printf("child: %d\n", t->parent.value);
}

void child_ctor_base(struct child *t, int v) {
base_ctor_base(&t->parent, v);
}
void child_ctor(struct child *t, int v) {
t->parent.vtable = &child_vtable_impl;
child_ctor_base(t, v);
}

int main() {
struct base b;
struct child c;
struct base *ref_c = &c.parent;

base_ctor(&b, 1);
child_ctor(&c, 2);

base_print(&b);
base_print(&c.parent);
base_print(ref_c);

/* Output:
* base 1
* child 2
* child 2
*/

}





Makes you feel a little bit sorry and thankful for your C++ compiler when you use virtual, no? In a system like what you're proposing the compiler would have to implement every function as virtual (look at Java for what that actually means) as there's no way to guess whether a class will be derived from or not upon its declaration.

(That took a while to type up, so I was beat to it ;).)

Share this post


Link to post
Share on other sites
i just compiled a test app that has a simple base class and a simple class deriving from it.

base class: Employee
derived class: Cashier

Employee has a function:
public virtual void draw()
{
// draw.
}

Cashier has a function:
public virtual void draw()
{
// draw.
}

this DOES NOT cause a compile-time error.
when i invoke the draw function from an instance of Cashier, then Cashier's draw is invoked. i can also invoke Employee's draw by simply making an explicity call to it (by type casting).

this makes me believe that the base virtual function draw() is indeed "hidden".

Share this post


Link to post
Share on other sites
Yup. C# requires override. It tosses a Warning, which you can (and should) configure to actually be an Error. C++ it'll not be hidden.

That code is wholy broken:

Employee Someone=new Cashier();
Someone.Draw();
// Employee.Draw() is run. Oops...

Share this post


Link to post
Share on other sites
"sealed override" means that you are overriding the method, but are 'sealing' it, so it's no longer overriable by derived classes. This is more useful to declare a class as sealed, which prevents other classes inheriting from it.

The thing I like a lot about .net is that everything is very explicit. Java's automatic virtualisation, while nice at times, could also be very confusing if you mistakenly override something. It also makes optimisation more difficult, inlining etc.
Also, on a similar note, being explicit helps to keep the 'black box' idea intact. If you have a public method in a class which, for example, ran security validation code, being able to explicitly seal the class is very useful. In java you could easily extend the class and replace all the methods with your own. This problem is actually quite difficult to solve in a design sense without explicit overriding/sealing.

Possibly the best bit is intergration with intellisense. Type in 'override' and it will pop up with a list of all virtual methods you can override in the class. :-) is most excellent in windows forms.

Share this post


Link to post
Share on other sites

This topic is 4205 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this