【问题标题】:Constant object cannot be passed as var parameter常量对象不能作为 var 参数传递
【发布时间】:2013-08-18 03:45:32
【问题描述】:

这是故障码..

multresult := mult(mult(temp, quatview), conjugate(temp));

完整程序

procedure TForm2.RotateCamera(var angle: Single; x: Single; y: Single; z: Single);
var
    temp, QuatView, multResult : TQuaternion;
begin
    temp.x := x * sin(Angle/2);
    temp.y := y * sin(Angle/2);
    temp.z := z * sin(Angle/2);
    temp.w := cos(Angle/2);

    quatview.x := camera1.Position.x;
    quatview.y := camera1.Position.y;
    quatview.z := camera1.Position.z;
    quatview.w := 0;

    multresult := mult(mult(temp, quatview), conjugate(temp));

    camera1.Position.x := multresult.x;
    camera1.Position.y := multresult.y;
    camera1.Position.z := multresult.z;
end;

多重功能

function TForm2.mult(var A: TQuaternion; B: TQuaternion) :TQuaternion;
 var
   c : TQuaternion;
begin
  C.x := A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
  C.y := A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
  C.z := A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
  C.w := A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
result := C;
End;

共轭

 function TForm2.conjugate( var quat:TQuaternion) :TQuaternion;
  begin
     quat.x := -quat.x;
     quat.y := -quat.y;
     quat.z := -quat.z;
     result := quat;
  end;

如果需要TQuaternion

type
  TQuaternion = class
    x: single;
    y: single;
    z: single;
    w: single;
  end;

知道为什么我会收到此错误以及如何修复它吗?

【问题讨论】:

    标签: delphi delphi-xe2


    【解决方案1】:

    您提出的问题的答案是,mult 的参数应该是 const。你不修改它们(你不应该),所以让它们成为常量。然后你的代码就编译好了。

    类似地,Conjugate 修改其输入参数是一种不好的形式。这使得该功能难以使用。不要那样做。

    考虑这一行:

    multresult := mult(mult(temp, quatview), conjugate(temp) );
    

    由于 conjugate 修改 temp,你最好希望 conjugate 的调用是在 temp 的其他使用之后进行的。语言没有这样的保证。所以,祈祷吧!

    算术代码值得遵循的原则之一是永远不应修改输入参数/操作数,并且函数始终返回值。遵循这个原则,你永远不会落入上面强调的陷阱。请参阅我的答案的第二部分以获取说明。

    但是,即使进行了这些更改,代码也无法工作,因为您没有实例化 TQuaternion 类的任何实例。你确定这不是记录吗?


    当你创建一个好的四元数类型时,真正的进步才会到来。这应该是一个值类型,因为出于多种原因,算术运算更适合值类型。

    在现代 Delphi 中,您希望将记录与运算符一起使用。这是您需要的一种风格,可以根据需要进行扩展。

    type
      TQuaternion = record
        x: single;
        y: single;
        z: single;
        w: single;
        function Conjugate: TQuaternion;
        class operator Multiply(const A, B: TQuaternion): TQuaternion;
      end;
    
    function TQuaternion.Conjugate: TQuaternion;
    begin
      Result.x := -x;
      Result.y := -y;
      Result.z := -z;
      Result.w := w;
    end;
    
    class operator TQuaternion.Multiply(const A, B: TQuaternion): TQuaternion;
    begin
      Result.x := A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
      Result.y := A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
      Result.z := A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
      Result.w := A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
    end;
    

    使用这种类型,您的乘法调用变为:

     multresult := temp*quatview*temp.Conjugate;
    

    您肯定想为这种类型编写更多的运算符和辅助函数。

    将算术函数移入这种类型并移出您的形式非常重要。不要使用您的高级 GUI 表单类来实现低级算术。

    最后一条建议。您的代码反复滥用 var 参数。我建议您将 var 参数视为要避免的事情。如果可能,请尝试在没有它们的情况下编写代码。

    【讨论】:

    • 谢谢,很好的建议。虽然我会再次尝试使用它......到目前为止,我必须找出如何将它与 firemonkey 相机一起使用......因为 FMX 有位置 (x,y,z) 和旋转位置(x,y,z) 虽然所有我能找到的例子使用opengl的外观(位置x,y,z,viewx,y,z,upx,y,z)所以工作弄清楚这一切..
    【解决方案2】:

    mult 方法将A 参数声明为var,因此您必须将变量传递给该方法才能工作,就像这样。

     multresult := mult(temp, quatview);
     multresult := mult(multresult, conjugate(temp));
    

    【讨论】:

    • @GlenMorse 我认为您将参数声明为 var 因为如果不是编译错误。尝试摆脱那个 var 就可以了
    • 我认为这个答案对问题的分析有点肤浅。是的,此更改将使代码编译。但是你会留下许多进一步的问题。即使这样,这里提出的解决方案也很差,因为要克服的第一个错误是错误使用 var 参数。这似乎是一个反复出现的主题。
    猜你喜欢
    • 2011-03-30
    • 2021-11-13
    • 2010-12-17
    • 2013-12-19
    • 2016-08-16
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    相关资源
    最近更新 更多