C ++ / CLI:如何重载操作符以接受引用类型? [英] C++/CLI: how to overload an operator to accept reference types?

查看:191
本文介绍了C ++ / CLI:如何重载操作符以接受引用类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建一个CLI值类c_Location与重载的运算符,但我认为我有一个问题与拳击。我已经实现了操作符重载,如许多手册中所见,所以我肯定这一定是正确的。
这是我的代码:

I am trying to create a CLI value class c_Location with overloaded operators, but I think I have an issue with boxing. I have implemented the operator overloading as seen in many manuals, so I'm sure this must be right. This is my code:

value class c_Location
{
public:
  double x, y, z;
  c_Location (double i_x, double i_y, double i_z) : x(i_x), y(i_y), z(i_z) {}

  c_Location& operator+= (const c_Location& i_locValue)
  {
    x += i_locValue.x;
    y += i_locValue.y;
    z += i_locValue.z;
    return *this;
  }
  c_Location operator+ (const c_Location& i_locValue)
  {
    c_Location locValue(x, y, z);
    return locValue += i_locValue;
  }
};

int main()
{
  array<c_Location,1>^ alocData = gcnew array<c_Location,1>(2);
  c_Location locValue, locValue1, locValue2;
  locValue = locValue1 + locValue2;
  locValue = alocData[0] + alocData[1];  // Error C2679 Binary '+': no operator found which takes a right-hand operand of type 'c_Location'
}

在搜索更长时间后,我发现错误来自操作数是一个引用类型,因为它是一个值类型的数组元素,并且函数只接受值类型非托管引用。我现在有2个可能性:

After searching for a longer time, I found that the error comes from the operand being a reference type, as it is an array element of a value type, and the function accepting only value types as it takes an unmanaged reference. I now have 2 possibiblities:


  1. c_Location 添加拆包main()中的错误行到

    locValue = alocData [0] +(c_Location)alocData [1];

  2. 修改运算符+重载,以便通过值而不是引用获取参数:

    c_Location运算符+(const c_Location i_locValue) li>
  1. adding a unboxing cast to c_Location and so changing the faulty line in main() to
    locValue = alocData[0] + (c_Location)alocData[1];
  2. modifying the operator+ overloading so that it takes the parameter by value instead of by reference:
    c_Location operator+ (const c_Location i_locValue)

这两个选项都可以工作,但就我所见,它们都有缺点:

opt 1意味着我必须显式转换到任何需要的位置。

opt 2意味着该函数将在其调用中创建参数的副本,因此浪费性能(不过很少)。

both options work, but as far as I can see, they both have disadvantages:
opt 1 means that I have to explicitly cast wherever needed.
opt 2 means that the function will create a copy of the parameter on its call and therefore waste performance (not much though).

我的问题:我的失败分析是否正确或失败是否有其他原因?

是否有更好的第三个选择?

如果不是:哪个选项,1或2,是更好的一个?我目前偏好#2。

My questions: Is my failure analysis correct at all or does the failure have another reason?
Is there a better third alternative?
If not: which option, 1 or 2, is the better one? I currently prefer #2.

推荐答案

TL; DR版本:

对于托管代码,请使用作为传递参考参数,而不是&

For managed code, use % for a pass by reference parameter, not &

您的诊断不完全正确。拳击与你的问题无关。但引用类型在某种程度上。

You diagnosis is not completely correct. Boxing has nothing to do with your problem. But reference types do, in a way.

当你说我发现错误来自操作数是一个引用类型时,你真的很接近。嗯,操作数是值类型而不是引用类型。但是当操作数存储在 引用类型内时,错误发生,因为它在垃圾回收堆(其中放置了引用类型的所有实例)的内部。这适用于数组以及包含值类型成员的自己的对象。

You were really close when you said that "I found that the error comes from the operand being a reference type". Well, the operand is a value type not a reference type. But the error occurs when the operand is stored inside a reference type, because then it's inside the garbage-collected heap (where all instances of reference types are placed). This goes for arrays as well as your own objects which contain a member of value type.

危险是当垃圾收集器运行时,它可以移动项目gc堆。这打破了本地指针( * )和引用(& ),因为它们存储地址,永远保持不变。为了处理这个问题,C ++ / CLI提供跟踪指针( ^ )和跟踪引用(垃圾收集器做两件事:

The danger is that when the garbage collector runs, it can move items around on the gc heap. And this breaks native pointers (*) and references (&), because they store the address and expect it to stay the same forever. To handle this problem, C++/CLI provides tracking pointers (^) and tracking references (%) which work together with the garbage collector to do two things:


  • 确保在使用它时不会释放包围对象

  • 如果垃圾回收器移动了封闭对象,则找到新地址

要使用C ++ / CLI, make operator + 一个非成员,就像普通的C ++一样。

For use from C++/CLI, you can make operator+ a non-member, just like normal C++.

value class c_Location
{
public:
    double x, y, z;
    c_Location (double i_x, double i_y, double i_z) : x(i_x), y(i_y), z(i_z) {}

    c_Location% operator+= (const c_Location% i_locValue)
    {
        x += i_locValue.x;
        y += i_locValue.y;
        z += i_locValue.z;
        return *this;
    }
};

c_Location operator+ (c_Location left, const c_Location% right)
{
    return left += right;
}

缺点是C#不会使用非成员, C#,把它写成一个非成员运算符(有两个显式操作数),但使它成为一个公共静态成员。

The drawback is that C# won't use non-members, for compatibility with C#, write it like a non-member operator (with two explicit operands) but make it a public static member.

value class c_Location
{
public:
    double x, y, z;
    c_Location (double i_x, double i_y, double i_z) : x(i_x), y(i_y), z(i_z) {}

    c_Location% operator+= (const c_Location% i_locValue)
    {
        x += i_locValue.x;
        y += i_locValue.y;
        z += i_locValue.z;
        return *this;
    }

    static c_Location operator+ (c_Location left, const c_Location% right)
    {
        return left += right;
    }
};

没有理由为 operator + = 因为C#无法识别,所以它将使用 operator + 并将结果分配给原始对象。

There's no reason to worry about this for operator+= since C# doesn't recognize that anyway, it will use operator+ and assign the result back to the original object.

对于如 double int 的原始类型,发现您还需要使用,但前提是您需要对该原始类型的实例的引用存储在托管对象中:

For primitive types like double or int, you may find that you need to use % also, but only if you need a reference to an instance of that primitive type is stored inside a managed object:

double d;
array<double>^ a = gcnew darray<double>(5);
double& native_ref = d; // ok, d is stored on stack and cannot move
double& native_ref2 = a[0]; // error, a[0] is in the managed heap, you MUST coordinate with the garbage collector
double% tracking_ref = d; // ok, tracking references with with variables that don't move, too
double% tracking_ref2 = a[0]; // ok, now you and the garbage collector are working together

这篇关于C ++ / CLI:如何重载操作符以接受引用类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆