C# 抽象类运算符重载
本文关键字:重载 运算符 抽象类 | 更新日期: 2023-09-27 18:37:10
我有一个抽象类,Vector,我想重载运算符+,-,*等。
我希望任何派生类都能够使用这些类,并获取与调用对象类型相同的对象。
我尝试使用泛型(简而言之,如下所示),但我找不到合法的方法:
public static T operator +<T>( T V1, T V2) where T : Vector
{
//some calculation
return new T(args);
}
然后我尝试仅使用基类来执行此操作:
public static Vector operator+(Vector V1, Vector V2)
{
if (V1.Dimension != V2.Dimension)
throw new VectorTypeException("Vector Dimensions Must Be Equal");
double[] ArgList = new double[V1.Dimension];
for (int i = 0; i < V1.Dimension; i++) { ArgList[i] = V1[i] + V2[i]; }
return (Vector)Activator.CreateInstance(V1.GetType(), new object[] { ArgList});
}
如果此方法在两个子对象中传递,则应对它们执行操作,并返回具有相同遗产的新对象。
我遇到的问题是,我无法强制所有此类子类都必须具有具有适当签名的构造函数,并且我无法调用基构造函数来制作对象。
有什么方法可以(a)使这些工作中的任何一个工作,或(b)以另一种方式优雅地做到这一点?
您可以声明子类可以覆盖的实例级抽象方法:
public abstract class Vector
{
protected abstract Vector Add(Vector otherVector);
public static Vector operator +(Vector v1, Vector v2)
{
return v1.Add(v2);
}
}
public class SubVector : Vector
{
protected override Vector Add(Vector otherVector)
{
//do some SubVector addition
}
}
可能会遇到一些问题,尤其是多个子类(SubVector
必须知道如何添加SomeOtherSubVectorClass
吗? 如果添加ThirdVectorType
类怎么办?也许可以处理空案例。 此外,确保SubVector.Add
在交换操作时的行为与SomeOtherSubVectorClass.Add
相同。
编辑:根据您的其他评论,您可以像这样:
public class Vector2D : Vector
{
public double X { get; set; }
public double Y { get; set; }
protected override Vector Add(Vector otherVector)
{
Vector2D otherVector2D = otherVector as Vector2D;
if (otherVector2D != null)
return new Vector2D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y };
Vector3D otherVector3D = otherVector as Vector3D;
if (otherVector3D != null)
return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = otherVector3D.Z };
//handle other cases
}
}
public class Vector3D : Vector
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
protected override Vector Add(Vector otherVector)
{
Vector2D otherVector2D = otherVector as Vector2D;
if (otherVector2D != null)
return new Vector3D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y, Z = this.Z };
Vector3D otherVector3D = otherVector as Vector3D;
if (otherVector3D != null)
return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = this.Z + otherVector3D.Z };
//handle other cases
}
}
编辑x2:
鉴于您的最新评论,也许您应该只维护一个内部数组/矩阵,然后只做通用矩阵数学。 子类可以针对数组指示公开 X/Y/Z 属性包装器:
public class Vector
{
protected double[] Values;
public int Length { get { return Values.Length; } }
public static Vector operator +(Vector v1, Vector v2)
{
if (v1.Length != v2.Length)
{
throw new VectorTypeException("Vector Dimensions Must Be Equal");
}
else
{
//perform generic matrix addition/operation
double[] newValues = new double[v1.Length];
for (int i = 0; i < v1.Length; i++)
{
newValues[i] = v1.Values[i] + v2.Values[i];
}
//or use some factory/service to give you a Vector2D, Vector3D, or VectorND
return new Vector() { Values = newValues };
}
}
}
public class Vector2D : Vector
{
public double X
{
get { return Values[0]; }
set { Values[0] = value; }
}
public double Y
{
get { return Values[1]; }
set { Values[1] = value; }
}
}
public class Vector3D : Vector
{
public double X
{
get { return Values[0]; }
set { Values[0] = value; }
}
public double Y
{
get { return Values[1]; }
set { Values[1] = value; }
}
public double Z
{
get { return Values[2]; }
set { Values[2] = value; }
}
}
EDITx3:根据你最新的评论,我想你可以在每个子类上实现运算符重载,在静态方法中执行共享逻辑(比如在基 Vector 类中),并在某个地方进行开关/大小写检查以提供特定的子类:
private static Vector Add(Vector v1, Vector v2)
{
if (v1.Length != v2.Length)
{
throw new VectorTypeException("Vector Dimensions Must Be Equal");
}
else
{
//perform generic matrix addition/operation
double[] newValues = new double[v1.Length];
for (int i = 0; i < v1.Length; i++)
{
newValues[i] = v1.Values[i] + v2.Values[i];
}
//or use some factory/service to give you a Vector2D, Vector3D, or VectorND
switch (newValues.Length)
{
case 1 :
return new Vector1D() { Values = newValues };
case 2 :
return new Vector2D() { Values = newValues };
case 3 :
return new Vector3D() { Values = newValues };
case 4 :
return new Vector4D() { Values = newValues };
//... and so on
default :
throw new DimensionOutOfRangeException("Do not support vectors greater than 10 dimensions");
//or you could just return the generic Vector which doesn't expose X,Y,Z values?
}
}
}
然后,您的子类将具有:
public class Vector2D
{
public static Vector2D operator +(Vector2D v1, Vector2D v2)
{
return (Vector2D)Add(v1, v2);
}
}
public class Vector3D
{
public static Vector3D operator +(Vector3D v1, Vector3D v2)
{
return (Vector3D)Add(v1, v2);
}
}
一些重复,但我看不到允许编译器执行此操作的方法:
Vector3 v1 = new Vector3(2, 2, 2);
Vector3 v2 = new Vector3(1, 1, 1);
var v3 = v1 + v2; //Vector3(3, 3, 3);
Console.WriteLine(v3.X + ", " + v3.Y + ", " + v3.Z);
或者对于其他尺寸:
Vector2 v1 = new Vector2(2, 2);
Vector2 v2 = new Vector2(1, 1);
var v3 = v1 + v2; //Vector2(3, 3, 3);
Console.WriteLine(v3.X + ", " + v3.Y); // no "Z" property to output!
有一个叫做Add()的抽象方法,operator+只是充当包装器怎么样? 即,"返回 v1。添加(v2)"。这也将使您能够定义非 Vector 类可以约束其代码的接口,从而能够执行类似数学的操作(因为泛型代码看不到/触摸任何类型的 +、- 等运算符)。
可以在泛型方法中使用的唯一构造函数是默认(即无参数)构造函数,您必须在方法/类型的泛型约束中指定该构造函数。
五年后,我遇到了完全相同的问题,只是我称它们为Ntuples,而不是向量。这是我所做的:
using System;
using System.Collections.Generic;
public class Ntuple{
/*parent class
has an array of coordinates
coordinate-wise addition method
greater or less than in dictionary order
*/
public List<double> Coords = new List<double>();
public int Dimension;
public Ntuple(List<double> Input){
Coords=Input;
Dimension=Input.Count;
}//instance constructor
public Ntuple(){
}//empty constructor, because something with the + overload?
public static Ntuple operator +(Ntuple t1, Ntuple t2)
{
//if dimensions don't match, throw error
List<double> temp = new List<double>();
for (int i=0; i<t1.Dimension; i++){
temp.Add(t1.Coords[i]+t2.Coords[i]);
}
Ntuple sum = new Ntuple(temp);
return sum;
}//operator overload +
public static bool operator >(Ntuple one, Ntuple other){
//dictionary order
for (int i=0; i<one.Dimension; i++){
if (one.Coords[i]>other.Coords[i]) {return true;}
}
return false;
}
public static bool operator <(Ntuple one, Ntuple other){
//dictionary order
for (int i=0; i<one.Dimension; i++){
if (one.Coords[i]<other.Coords[i]) {return true;}
}
return false;
}
}//ntuple parent class
public class OrderedPair: Ntuple{
/*
has additional method PolarCoords, &c
*/
public OrderedPair(List<double> Coords) : base(Coords){}
//instance constructor
public OrderedPair(Ntuple toCopy){
this.Coords=toCopy.Coords;
this.Dimension=toCopy.Dimension;
}
}//orderedpair
public class TestProgram{
public static void Main(){
List<double> oneCoords=new List<double>(){1,2};
List<double> otherCoords= new List<double>(){2,3};
OrderedPair one = new OrderedPair(oneCoords);
OrderedPair another = new OrderedPair(otherCoords);
OrderedPair sum1 = new OrderedPair(one + another);
Console.WriteLine(one.Coords[0].ToString()+one.Coords[1].ToString());
Console.WriteLine(sum1.Coords[0].ToString()+sum1.Coords[1].ToString());
bool test = one > another;
Console.WriteLine(test);
bool test2 = one < another;
Console.WriteLine(test2);
}
}
}//namespace ntuples