Jump to content
  • Advertisement
Sign in to follow this  
GekkoCube

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

This topic is 4486 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
Advertisement
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
one more thing...

if suppose both my base class and my derived class has a virtual draw() function,

this means the base draw() is "hidden", right?

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
No, it is overriden. C# should flag it as an error if you simply declared the derived method 'virtual'.

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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!