When an instance method declaration includes a virtual
modifier, the method is said to be a virtual method.
When no virtual
modifier is present, the method is said to be a non-virtual
method.
When a virtual method is invoked, the run-time
type of the instance for which that invocation takes place determines
the actual method implementation to invoke. In a nonvirtual method invocation,
the compile-time type of the instance is the
determining factor.
A virtual method can be overridden
in a derived class. When an instance method declaration includes an override
modifier, the method overrides an inherited virtual method with the same
signature. Whereas a virtual method declaration introduces a new
method, an override method declaration specializes an existing
inherited virtual method by providing a new implementation of that method.
An abstract method is a virtual
method with no implementation. An abstract method is declared with the abstract
modifier and is permitted only in a class that is also declared abstract. An
abstract method must be overridden in every non-abstract derived class.
The following example declares an abstract class, Expression,
which represents an expression tree node, and three derived classes, Constant, VariableReference,
and Operation,
which implement expression tree nodes for constants, variable references, and
arithmetic operations.
using System;
using System.Collections;
using System.Collections;
public abstract class Expression
{
public abstract double Evaluate(Hashtable vars);
}
{
public abstract double Evaluate(Hashtable vars);
}
public class Constant: Expression
{
double value;
{
double value;
public Constant(double
value) {
this.value = value;
}
this.value = value;
}
public override double
Evaluate(Hashtable vars) {
return value;
}
}
return value;
}
}
public class VariableReference: Expression
{
string name;
{
string name;
public
VariableReference(string name) {
this.name = name;
}
this.name = name;
}
public override double
Evaluate(Hashtable vars) {
object value = vars[name];
if (value == null) {
throw new Exception("Unknown variable: " + name);
}
return Convert.ToDouble(value);
}
}
object value = vars[name];
if (value == null) {
throw new Exception("Unknown variable: " + name);
}
return Convert.ToDouble(value);
}
}
public class Operation: Expression
{
Expression left;
char op;
Expression right;
{
Expression left;
char op;
Expression right;
public
Operation(Expression left, char op, Expression right) {
this.left = left;
this.op = op;
this.right = right;
}
this.left = left;
this.op = op;
this.right = right;
}
public override double
Evaluate(Hashtable vars) {
double x = left.Evaluate(vars);
double y = right.Evaluate(vars);
switch (op) {
case '+': return x + y;
case '-': return x - y;
case '*': return x * y;
case '/': return x / y;
}
throw new Exception("Unknown operator");
}
}
double x = left.Evaluate(vars);
double y = right.Evaluate(vars);
switch (op) {
case '+': return x + y;
case '-': return x - y;
case '*': return x * y;
case '/': return x / y;
}
throw new Exception("Unknown operator");
}
}
The previous four classes can be used to model arithmetic
expressions. For example, using instances of these classes, the expression x + 3 can be
represented as follows.
Expression e = new Operation(
new VariableReference("x"),
'+',
new Constant(3));
new VariableReference("x"),
'+',
new Constant(3));
The Evaluate
method of an Expression
instance is invoked to evaluate the given expression and produce a double value.
The method takes as an argument a Hashtable that contains variable names
(as keys of the entries) and values (as values of the entries). The Evaluate method
is a virtual abstract method, meaning that non-abstract derived classes must
override it to provide an actual implementation.
A Constant’s
implementation of Evaluate
simply returns the stored constant. A VariableReference’s implementation looks
up the variable name in the hashtable and returns the resulting value. An Operation’s
implementation first evaluates the left and right operands (by recursively
invoking their Evaluate
methods) and then performs the given arithmetic operation.
The following program uses the Expression classes to evaluate the
expression x
* (y + 2) for
different values of x
and y.
using System;
using System.Collections;
using System.Collections;
class Test
{
static voidMain ()
{
{
static void
Expression e =
new Operation(
new VariableReference("x"),
'*',
new Operation(
new VariableReference("y"),
'+',
new Constant(2)
)
);
new VariableReference("x"),
'*',
new Operation(
new VariableReference("y"),
'+',
new Constant(2)
)
);
Hashtable vars =
new Hashtable();
vars["x"]
= 3;
vars["y"] = 5;
Console.WriteLine(e.Evaluate(vars)); // Outputs "21"
vars["y"] = 5;
Console.WriteLine(e.Evaluate(vars)); // Outputs "21"
vars["x"]
= 1.5;
vars["y"] = 9;
Console.WriteLine(e.Evaluate(vars)); // Outputs "16.5"
}
}
vars["y"] = 9;
Console.WriteLine(e.Evaluate(vars)); // Outputs "16.5"
}
}
Comments
Post a Comment