Dennis said:
You need to create 2 class instances when creating an instance
of a class which is derived from an abstract class.
No you don't. You end up defining two types, but you only create one
instance.
Here's an example:
public abstract class ABC
{
public abstract void SayHello();
}
public class ConcreteDerived : ABC
{
public override void SayHello() { Console.WriteLine("Hello!"); }
}
And now to use this:
ABC obj = new ConcreteDerived();
obj.SayHello();
I have created just one instance here. I have defined two classes, but I've
only created one instance. (In fact it's impossible to create an instance of
the base class, ABC, because it's abstract. So I couldn't create an instance
of each even if I wanted to.)
(Note, by the way, that this doesn't actually solve the problem as
originally stated. Abstract Base Classes aren't a solution to this
particular issue because you can't inherit constructor signatures.)
Creating an instance of an abstract class means performance
overhead.
I think that is especially true if the abstract class contains
virtual methods.
You can't create an instance of an abstract class. That's what 'abstract'
means!
Also, the presence of virtual methods has no impact on the overhead of
creating an instance of a class, so your argument is slightly confused here
I'm afraid.
There are overheads to virtual methods, but you've missed an important point
here:
Virtual methods always means performance overhead.
According to Microsoft they are two times as expensive as
non-virtual methods.
Yes, but interfaces are even more expensive.
So if you chose to use interfaces instead of abstract base classes to avoid
the overhead of a virtual function call, you've made a bad choice.
Interface method calls are even more expensive than virtual function calls.
The expensive thing is the polymorphic nature of the call. With either
interfaces or virtual methods, the method that ends up getting called will
depend on what type of object you've got, so the JIT-compiled code can't
just call the relevant function directly or inline it. You pay that cost
with either virtual methods or interfaces. And as it happens, interface
method calls are marginally the more expensive of these two call types
today.
(In Whidbey, the next version of .NET, it all gets a little more complex to
work out how much a method call costs, because they appear to detect when
you're not actually exploiting polymorphism and change the way the code
works. It's similar to a technique called 'monomorphic inlining' that some
JVMs use. This means that the cost of polymorphic function calls changes
over time.)
However, abstract members should be as fast as interface members i
believe.
Abstract members *are* virtual. If you use ILDASM to look at what the
compiler generates, this becomes very clear. For example, here's the
abstract SayHello method as defined in my ABC class above:
..method public hidebysig newslot abstract virtual
instance void SayHello() cil managed
{
} // end of method ABC::SayHello
Notice that it is marked as 'abstract virtual'. In the IL, this is
explicit. With C#, to save you typing, they don't make you type in both -
abstract methods *have* to be virtual. A non-virtual abstract method makes
no sense: 'abstract' effectively means 'must override', and you can only
override virtual methods. So if you were to define a non-virtual abstract
method you would effectively be defining a method that derived classes were
required to override, but which couldn't be overridden!
So because 'abstract' only makes sense for virtual methods, in C# writing
'abstract' always implies 'virtual'.
So abstract methods are exactly as expensive as virtual methods, for the
simple reason that they *are* virtual methods.
An abstract class containing no virtual methods should be nearly as
fast as an interface, but still slower.
An abstract class containing no virtual methods would be a slightly unusual
thing, because it would contain no abstract methods... It is actually
possible to write such a class, you just wouldn't normall do it. It would
in fact be substantially faster to use than call interface methods, because
non-virtual methods (which includes all non-abstract methods) are faster
than either virtual methods or interface method calls. But it wouldn't be a
very useful thing - you don't often want to declare an abstract class with
no abstract methods.
But how would an abstract class containing some abstract methods stack up
against an interface? In the current version of the CLR, interface calls are
known to be slightly more expensive, so you would expect this:
Fastest: direct call to non-abstract, non-virtual, non-interface methods
2nd fastest: call through abstract or virtual method
Slowest: call through interface method
But it's always important to test, so I wrote a little program that sees how
many calls a second I can get through each type. Here are the results:
Direct call: 515 million calls per second
Abstract method: 173 million calls per second
Interface method: 155 million calls per second
That's on my laptop, with a 1.6GHz Pentium M, running v1.1 of the .NET
framework. I've copied the program at the end of this message so you can
try it out.
This seems to confirm that interfaces are (on the current .NET framework)
the slowest of the three options. And for this particular test, a
non-abstract, non-interface call is well over twice as fast.
In any case, not only is this not really relevant to the original discussion
(abstract base classes don't help solve the problem any better than
interfaces) this is a bit of a case of micro-optimization. The difference in
performance between these different types of method calls is very often
going to be irrelevant - if the method does anything non-trivial, then the
cost of the work it does will swamp any difference between invocation costs.
(These distinctions really only matter for very simple methods like
straightforward property accessors. In that case, the main difference is
that with a non-interface and non-virtual call, the JIT compiler can inline
the method.)
--
Ian Griffiths -
http://www.interact-sw.co.uk/iangblog/
DevelopMentor -
http://www.develop.com/
using System;
public abstract class ABC
{
public abstract void SayHello();
}
public interface IFoo
{
void SayHello();
}
public class ConcreteDerived : ABC
{
public override void SayHello() { }
}
public class InterfaceImpl : IFoo
{
public void SayHello() { }
}
public class NonVirtual
{
public void SayHello() { }
}
class App
{
static void Main()
{
// Run tests multiple times to avoid any transient
// JIT-related overheads
for (int i = 0; i < 5; ++i)
{
SpeedTestNonVirtual(new NonVirtual());
SpeedTestABC(new ConcreteDerived ());
SpeedTestInterface(new InterfaceImpl ());
}
}
const int CallsBetweenTimeChecks = 100000;
static void SpeedTestNonVirtual(NonVirtual obj)
{
DateTime stopBy = DateTime.Now + TimeSpan.FromSeconds(10);
long count = 0;
while (DateTime.Now < stopBy)
{
// Make lots of calls in between time checks, otherwise
// the time take to check the current time dominates.
for (int i = 0; i < CallsBetweenTimeChecks; ++i)
{
obj.SayHello();
count += 1;
}
}
Console.WriteLine("Non-virtual: {0} million calls per second", ((double)
count) / 10000000.0);
}
static void SpeedTestABC(ABC obj)
{
DateTime stopBy = DateTime.Now + TimeSpan.FromSeconds(10);
long count = 0;
while (DateTime.Now < stopBy)
{
// Make lots of calls in between time checks, otherwise
// the time take to check the current time dominates.
for (int i = 0; i < CallsBetweenTimeChecks; ++i)
{
obj.SayHello();
count += 1;
}
}
Console.WriteLine("ABC: {0} million calls per second", ((double) count)
/ 10000000.0);
}
static void SpeedTestInterface(IFoo obj)
{
DateTime stopBy = DateTime.Now + TimeSpan.FromSeconds(10);
long count = 0;
while (DateTime.Now < stopBy)
{
// Make lots of calls in between time checks, otherwise
// the time take to check the current time dominates.
for (int i = 0; i < CallsBetweenTimeChecks; ++i)
{
obj.SayHello();
count += 1;
}
}
Console.WriteLine("Interface: {0} million calls per second", ((double)
count) / 10000000.0);
}
}