Reputation: 3970
I seem to have forgotten some of the most basic rules of inheritance because I can't figure out why this won't work. I have a class SuffixNode which extends Node.
Node:
class Node
{
public char label;
public Node parent;
public Dictionary<char,Node> children;
public Node(Node NewParent, char NewLabel)
{
this.parent = NewParent;
this.label = NewLabel;
children=new Dictionary<char,Node>();
}
}
SuffixNode:
class SuffixNode: Node
{
public Dictionary<String, int> Location=new Dictionary<String, int>();
public SuffixNode(Node NewParent):base(NewParent, '$')
{
}
public void AddLocation(String loc,int offset)
{
this.Location.Add(loc, offset);
}
}
I'm trying to call the AddLocation method in the main program from the SuffixNode class but it gives me an error saying that no such method exists (in Node class):
Node n;
char FirstChar = suffix[0]; //first character of the suffix
if (suffix == "")
{
return true;
}
//If the first character of a suffix IS NOT a child of the parent
if (!parent.children.ContainsKey(FirstChar))
{
if (FirstChar == '$')
{
n = new SuffixNode(parent);
n.AddLocation(document, offset);
}
else
{
n = new Node(parent, FirstChar); //Create a new node with the first char of the suffix as the label
parent.children.Add(FirstChar, n); //Add new node to the children collection of the parent
}
}
I'm sure it's an extremely simple answer, but I just can't realise why this isn't working. Shouldn't
Node n = new SuffixNode(parent)
allow me to access the SuffixNode methods and variables?
Upvotes: 1
Views: 1459
Reputation: 43056
Many answers have correctly stated that you cannot call a method defined in a derived class on a variable whose type is the base class. None has noted that this is fundamental to the type safety provided by C#'s static typing.
When you call a method on a variable, that method call is resolved at compile time, and there's no way the compiler can resolve n.AddLocation
when n
is a Node
-type variable.
The alternative would be to resolve the call at run-time, which could result in an exception if the referent of n
is an instance of some other subclass of Node
that doesn't have an AddLocation
method (or indeed an instance of Node
itself). The C# type system is explicitly designed to avoid that situtation.
Consider:
object o1 = "Hello, World!";
Console.WriteLine(o1.Length); //hypothetically fine
object o2 = Math.PI;
Console.WriteLine(o2.Length); //exception!
The philosophy of C# is fail fast: catch coding errors at compile time whenever possible, because errors caught at compile time are much easier to fix than those caught at run time.
The trivial solution, without changing your object model, would be to introduce a new variable inside the relevant block:
if (FirstChar == '$')
{
SuffixNode sn = new SuffixNode(parent);
sn.AddLocation(document, offset);
n = sn;
}
else
{
n = new Node(parent, FirstChar); //Create a new node with the first char of the suffix as the label
parent.children.Add(FirstChar, n); //Add new node to the children collection of the parent
}
Upvotes: 1
Reputation: 124742
You have declared n
as a Node
. Node
does not contain a definition for AddLocation
, so your code will not compile. Even though you know that the actual, underlying type is a SuffixNode
, the compiler has to stick to its guns and call you out on the error.
Imaging this scenario:
class OtherNode : Node
{
}
Node n = new OtherNode();
n.AddLocation(...);
Should that work? Certainly not, but what rule would omit that code from compiling and allow your example? How can the compiler possibly know that you didn't swap the underlying type at a later point in the program? It can't.
You're going the wrong way; if this method should be available to all descendants of Node
then it needs to at least be declared in Node
(it can be abstract as to be overriden in derived classes).
Upvotes: 1
Reputation: 2479
If you define a virtual method in Node, and override it in SuffixNode, the SuffixNode version will be called in your scenario. If, as in your case, the method doesn't exist in Node, it can't be called in that way, because the variable n could be holding any kind of Node. In order to call the method, you first must cast it to SuffixNode.
Upvotes: 2
Reputation: 19223
Shouldn't
Node n = new SuffixNode(parent)
allow me to access the SuffixNode methods and variables?
No, the type of variable defines what methods you have access to.
You will need to change the type of the variable to SuffixNode
if you want access to it.
Alternatively you can add it to the base class if that makes more sense.
Upvotes: 1
Reputation: 1167
You've declared the type of n as Node
, which in fact does not have an AddLocation method. You have to declare it as SuffixNode n = new SuffixNode(parent)
to be able to call the child's function on it, or else add a (perhaps abstract) method to Node
called AddLocation
.
Upvotes: 5
Reputation: 27619
Node n=new SuffixNode(parent)
This line is telling the compiler that n is of type Node
. The fact that it currently has a SuffixNode
assigned to it is irrelevant. All the compiler knows is its a Node
and thus you can only call Node
members on it.
Probably the easiest way to get around this is:
n = new SuffixNode(parent);
((SuffixNode)n).AddLocation(document, offset);
This basically tells the compiler that you really have a suffix node here.
Possibly more clear would be:
SuffixNode sn = new SuffixNode(parent);
sn.AddLocation(document, offset);
n = sn;
Upvotes: 3