我正在研究矩阵/向量类,其中一部分具有运算符重载。奇怪的事情之一是,不是返回一个新的对象(在本例中为vector),而是对该向量进行了变异,并返回了一个新的对象。如何干净地返回Vector的新实例?
这是构造函数:
private List<double> v = new List<double>();
private int dims;
public Vector(double[] a)
{
foreach (double d in a)
{
v.Add(d);
dims++;
}
}
public Vector(int dims)
{
var a = new double[dims];
v = a.ToList();
this.dims = dims;
}
private Vector(List<double> a)
{
v = a;
dims = a.Count;
}
和运算符重载(仅发布加法,因为它们全部都有问题,并且结构相似,因此应该有相同的解决方案)
public static Vector operator + (Vector a, Vector b)
{
Vector c = new Vector();
c = a;
for (int dim = 0; dim < c.dims; dim++)
{
c[dim] += b[dim];
}
return c;
}
编辑:因此,我将类更改为结构,似乎仍然有问题。也许是因为变量v
是一个列表,因此它是一个类,仍在传递对列表的引用吗?也许我必须使用数组而不是列表?
答案 0 :(得分:3)
该行:
c = a;
是问题。
然后c
和a
都指向同一个对象。
可能的解决方案:
1)将Vector从类更改为结构。
2)使用您的构造函数之一创建一个新的Vector对象:
公共静态矢量运算符+(矢量a,矢量b)
{
Vector c = new Vector(a.v);
for (int dim = 0; dim < c.dims; dim++)
{
c[dim] += b[dim];
}
return c;
}
答案 1 :(得分:3)
问题是您的c = a
“复制”了地址而不是值。您的+
运算符应如下所示:
public static Vector operator + (Vector a, Vector b)
{
if (a.dims != b.dims)
throw new WhatEverException();
Vector c = new Vector(a.dims);
// c = a
for (int dim = 0; dim < c.dims; dim++)
{
// c[dim] += b[dim];
c[dim] = a[dim] + b[dim];
}
return c;
}
小加号:您可以将您的dims
成员更改为只读属性:
private int dims { get { return v.Count; } }
如何测试:
public class Vector
{
public char Id { get; set; } // just for debug
public double this[int i] { get { return Values[i]; } set { Values[i] = value; } }
private List<double> Values { get; set; }
public int Dim { get { return Values.Count; } }
public Vector(double[] values) { Values = values.ToList(); }
public Vector(int dims) { Values = new double[dims].ToList(); }
// note this constructor, the one you posted actually copy the whole list object
public Vector(List<double> values) { Values = new List<double>(values); }
public static Vector operator +(Vector a, Vector b)
{
if (a.Dim != b.Dim)
throw new Exception();
Vector c = new Vector(a.Dim) { Id = 'c' };
for (int i = 0 ; i < c.Dim ; i++)
c[i] = a[i] + b[i];
return c;
}
}
static void Main(string[] args)
{
Vector a = new Vector(new double[] { 1.42857, 1.42857, 1.42857 }) { Id = 'a' };
Vector b = new Vector(new double[] { 1.42857, 2.85714, 4.28571 }) { Id = 'b' };
Vector c = a + b;
Console.WriteLine(string.Format(">{0} = {1} + {2}", c.Id, a.Id, b.Id));
Console.WriteLine(string.Format(">{1} + {2} = {0}", c[0], a[0], b[0]));
Console.WriteLine(string.Format(">{1} + {2} = {0}", c[1], a[1], b[1]));
Console.WriteLine(string.Format(">{1} + {2} = {0}", c[2], a[2], b[2]));
Console.ReadKey();
}
结果:
>c = a + b
>1.42857 + 1.42857 = 2.85714
>1.42857 + 2.85714 = 4.28571
>1.42857 + 4.28571 = 5.71428
答案 2 :(得分:1)
您应该将所有向量a
的值复制到向量c
,或将Vector
更改为struct而不是class。
这样做a = c
会使c
引用a
,因此对c
的所有修改也将应用于a
。发生这种情况的原因是Vector
是一个类,并且将其作为引用而不是值进行传递。
解决此问题的一种方法是遍历所有a
值并将它们添加到c
中。或者,更好的是,您有构造函数为您完成了此操作,因此您的最终运算符覆盖应类似于
public static Vector operator + (Vector a, Vector b)
{
// Will work, because you are still inside Vector class and you can access all private members.
Vector c = new Vector(a.v);
for (int dim = 0; dim < c.dims; dim++)
c[dim] += b[dim];
return c;
}
答案 3 :(得分:0)
您可以使用Zip
添加两个列表的元素。另外,您可以使用AddRange
而不是循环。
class Vector
{
private List<double> v = new List<double>();
private int dims;
public Vector(double[] a)
{
v.AddRange(a);
}
public Vector(int dims)
{
var a = new double[dims];
v = a.ToList();
this.dims = dims;
}
private Vector(List<double> a)
{
v = new List<double>(a);
dims = a.Count;
}
public static Vector operator +(Vector a, Vector b)
{
var ls = a.v.Zip(b.v, (x, y) => x + y).ToList();
return new Vector(ls);
}
}
答案 4 :(得分:0)
好的,我已经完成了一些工作。这有点杂乱,但是可以用。而且我不知道为什么我必须跳很多圈才能使此功能正常工作,但这是我的解决方案:
public static Vec operator + (Vec a, Vec b)
{
Vec c = new Vec();
c.v = new List<double>();
for (int dim = 0; dim < a.Dims; dim++)
{
c.v.Add(a[dim] + b[dim]);
}
return c;
}
我不确定是否有更优雅的方法来做到这一点,但是,嘿,它可行。我也将它设为结构而不是类。