Monday, December 01, 2003

Polymorphism: C++ vs Java vs C#

As mentioned earlier, all three languages provide support for polymorphism. But to enable it, each language requires different syntax.

C++ as we've seen requires a "virtual" keyword in the base class. To override this virtual method you only require to declare a method with the same signature in a derived class. The "virtual" keyword is optional.

class Base
{
public:
virtual void fun() { std::cout << "Base::fun"; }
};

class Derived : public Base
{
public:
/* virtual */ void fun() { std::cout << "Derived::fun"; }

void fun2() { std::cout << "Derived::fun2"; }
};

Base* p;

p = new Base;
p->fun(); // Base's fun()

p = new Derived;
p->fun(); // Derived's fun()

In Java, ALL methods are virtual by default. NO extra keywords are required to enable polymorphism.

public class Base
{
public void fun() { System.out.print( "Base.fun" ); }
}

public class Derived extends Base
{
public void fun() { System.out.print( "Derived.fun" ); }

public void fun2() { System.out.print( "Derived.fun2" ); }
}

Base p;

p = new Base();
p.fun(); // Base's fun()

p = new Derived();
p.fun(); // Derived's fun()

In C# you need TWO keywords to enable polymorphism. In the base class you have to declare a function to be virtual using "virtual". In a derived class you have to explicitly specify that you intend to override a method using "override".

public class Base
{
public virtual void fun() { System.Console.Write( "Base.fun" ); }
}

public class Derived : Base
{
public override void fun() { System.Console.Write( "Derived.fun" ); }

public void fun2() { System.Console.Write( "Derived.fun2" ); }
}

Base p;

p = new Base();
p.fun(); // Base's fun()

p = new Derived();
p.fun(); // Derived's fun()

It's interesting to compare and constract between the different languages and to understand why they chose to do what they did.

C++, as always, is most concerned about space and efficiency. It will ONLY have the overhead of the vtable pointer IF you have any virtuals in there. All methods will be resolved at compile time, statically, by default, unless they are virtual.

Java, on the other hand, concerned most with simplicity, defines all methods virtual. This means that ALL classes regardless of whether they need it or not will have v-tables. Efficiency suffers since ALL method calls will have an indirection. You could explicitly include the keyword "final" which is really the opposite of virtual. This will make the call static and will allow the compiler to resolve it at compile time. So, in Java, all methods will be resolved at run time, dynamically, by default, unless they are final.

Finally we have C#, which goes back to C++ roots. It too will have v-tables ONLY if there are virtual functions in the class. But why introduce the "override" keyword? This is to help with versioning of components. Consider this...

You develop a class which has a bunch of virtual methods. You derive from that class and override whatever you need. All is good... the derived class behaves well. Now, you also define a completely independant new method in the derived class. Sometime later, the Base class designer decides to add a new virtual method with that same name to the Base class. Now, that completely independant method in the Derived class is "unintentially" overriding the new Base class virtual method. More likely than not, it is NOT the correct behavior since it had no idea it was overriding anything. This will happen in both C++ as well as in Java. More easily in Java, since ALL methods are virtual by default. In C++, you have to explicitly say that it's virtual. C# won't have this problem since, you need the "override" keyword in the derived classes.

Extending the above examples...

In C++, if you add a new virtual method to the Base class...

virtual void fun2() { std::cout << "Base::fun2;" }

and in Java if you add a new method to the Base class...

public void fun2() { System.out.print( "Base.fun2" ); }

then the corresponding fun2()'s in Derived will automatically override these.

If you add a new virtual method to the Base class in C#

public virtual void fun2() { System.Console.Write( "Base.fun2" ); }

the compiler will generate a warning (NOT error) telling you that you need to be more explicit about what you are intending to do. Either add the "override" keyword to the derived class method fun2() saying that you DO want polymorphic behavior OR add the "new" keyword saying that you DON'T want polymorphic behavior and that you just want to shadow Base's fun2().

8 comments:

wow power leveling said...

welcome to the wow power leveling, cheap service site, buy cheap wow gold,wow gold,world of warcraft power leveling buy wow power leveling

Anonymous said...

Excellent article.

Hitesh Kumar said...

Polymorphism in java
this blog is simple and helpful

hitesh Kumar said...

polymorphism in c++
Thanks for sharing this post

Hitesh Kumar said...

Polymorphism in C++

Great post

akmal niazi khan said...

This blog awesome and i learn a lot about programming from here.The best thing about this blog is that you doing from beginning to experts level.

Love from

Lars Undebakke said...

This cleared things up for me, thanks :)

Rachel Lancaster said...

Nice Article!_