Reputation: 161
When posting this question my hope was to find a way how to reference/point to an abstract class that that could be used by a worker/holder.
As the comments by @progman suggested and @laryx-decidua there is no way to hold a reference to an abstract class, but one can only hold a reference to a instantiated object.
Below you can find what I think is their proposed solution. To me this is an ugly solution, and I would have liked to have one that derives multiple static classes from an abstract base class and the holder gets references to those static classes to do its work. Deriving a static class form an abstract class Why you can't drive a static class is it seems prohibited by design and indicates bad architecture; although I don't see why the solution above is any better.
Suggested Solution
using System;
using System.Collections.Generic;
public abstract class BaseClass
{
// Some declarative knowledge
public int value;
protected BaseClass(int value){
this.value = value;
}
// Some procedural
public abstract void execute();
}
public class ConcreteClass1 : BaseClass
{
public ConcreteClass1() : base(42) {}
public override void execute()
{
Console.WriteLine("In Concrete1! Value " + value);
}
}
public class ConcreteClass2 : BaseClass
{
public ConcreteClass2() : base(8888) { }
public override void execute()
{
Console.WriteLine("In Concrete2! Value " + value);
}
}
public class Holder
{
BaseClass activeClass;
public void setClass(BaseClass newClass){
activeClass = newClass;
}
public void doWork()
{
int x;
activeClass.execute();
x = activeClass.value * activeClass.value;
Console.WriteLine("Holder has done its work: " + x);
}
}
class MainClass
{
static void Main(string[] args)
{
List<BaseClass> classes = new List<BaseClass>();
classes.Add(new ConcreteClass1());
classes.Add(new ConcreteClass2());
Holder holder = new Holder();
holder.setClass(classes[0]);
holder.doWork();
holder.setClass(classes[1]);
holder.doWork();
holder.setClass(classes[0]);
holder.doWork();
}
}
producing
In Concrete1! Value 42
Holder has done its work: 1764
In Concrete2! Value 8888
Holder has done its work: 78996544
In Concrete1! Value 42
Holder has done its work: 1764
Upvotes: 1
Views: 1435
Reputation: 9680
Disclaimer: I don't speak C#, but I suspect the situation is similar to C++. The rest of the answer is based on my C++ and general OOP experience.
If I understood you correctly, you'd like to hold derived class object(s) through a base class reference and invoke a polymorphic ("virtual") method on those objects. Because you expect those derived classes to be "stateless" (i.e. no data members), you thought maybe you could "get away with" static (and/or abstract) classes.
The problem is that you need to instantiate something to put into your Holder
objects, because a reference (or a pointer) can refer to (point to) only to a concrete object. So you need to instantiate objects that will be referred to via a reference in Holder
, as some of the commenters have already pointed out. That's why abstract classes won't do -- they cannot be instantiated.
If there were an OOP language that supports references to types , plus some mechanism that can do the following: "Hmm, here is a reference AnimalTypeRef
to the (possibly abstract) base class type Animal
. AnimalTypeRef
actually refers to the derived class type Elephant
. Now, the user wants to invoke a virtual method Animal::make_noise()
that does not use any class state, so let's invoke the corresponding method Elephant::make_noise()
that overrides it and returns this :-)." -- well, then you could do what you have asked for.
I suspect this has not been implemented in C++ or C# because there are not too many use cases for it, and actually the same thing can be done with the general mechanism that requires that references refer to concrete objects.
Just go ahead and derive concrete (non-abstract) classes from your abstract base class, and don't worry about their statelessness. It's perfectly OK to define and use concrete objects that have no data members. Instantiate them, then initialise a Holder
object with them, using a reference to the (abstract) base class and that's it. Polymorphic method invocation through base class references will do the rest.
Upvotes: 0