我有一个抽象类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)以另一种方式优雅地做到这一点?
答案 0 :(得分:11)
您可以声明子类可以覆盖的实例级抽象方法:
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
}
}
EDITx2:
鉴于你的最新评论,也许你应该维护一个内部数组/矩阵,只做通用矩阵数学。您的子类可以针对数组指示公开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!
答案 1 :(得分:0)
如果有一个名为Add()的抽象方法,那么operator +只是作为包装器?即,“return v1.Add(v2)”。这也使您能够定义非Vector类可以约束其代码的接口,从而能够执行类似数学的操作(因为通用代码无法查看/触摸任何类型的+, - 等运算符)。
您可以在泛型方法中编写的唯一构造函数是默认(即无参数)构造函数,您必须在方法/类型的泛型约束中指定。
答案 2 :(得分:0)
五年后,我遇到了完全相同的问题,只是我称他们为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