2015-10-03 4 views
2

У меня есть определенный тип данных и глобальная переменная указанного типа. Я передаю эту глобальную переменную в качестве аргумента нескольким методам, значение переменной кажется непреднамеренно измененным.Как передать объект переменной в качестве аргумента значения

Я обнаружил, что все объекты передаются в качестве ссылочных параметров, даже если они не объявлены как параметры var (или, как я полагаю).

Итак, я попытался исправить проблему, введя локальную переменную ко всем методам, в которые я передаю объект, а затем назначил локальную переменную параметру и затем объявлял параметр объекта как const, но значение глобальная переменная все еще меняется, как мне ее преодолеть?

{unit something} 
interface 

    uses 
     SysUtils 

    type 
     ByteArr = Array of Byte; 
     Num = record 
     sign : byte; 
     int : ByteArr; 
     frac : ByteArr; 
     end; 

    function StrToNum(input : string):Num; 
    function NumToStr(input : Num):string; 
    function Dostuff(const a : Num):Num 

implementation 

    function StrToNum(input : string):Num; 
    begin 
     //code to convert a string into 'Num' type 
    end; 

    function NumToStr(input : Num):string; 
    begin 
     //code to output a string version of a 'Num' input 
    end; 

    function Dostuff(const a : Num):Num 
    var 
     somevar : num; 
    begin 
     somevar := a; 
     code; //code to change value of 'somevar' 
     result := somevar; 
    end;  

end. 

{console program} 
uses 
    something in 'something.pas'; 
var 
    globalvar : num; 

begin 
    globalvar := StrToNum('2'); 
    writeln(NumToStr(globalvar)); //shows 2 
    writeln(NumToStr(Dostuff(globalvar))); //shows correct value 
    writeln(numtostr(globalvar)); //no longer displays 2 
end. 

ответ

1

Динамический массив является ссылочным типом. Ваш тип ByteArr является динамическим массивом и, следовательно, ссылочным типом. Присвоение переменных такого типа является назначением ссылок, а не присвоением значений.

Рассмотрим этот код:

var 
    A, B: ByteArr; 
.... 
SetLength(A, 1); 
A[0] := 0; 
B := A; 
Writeln(A[0]); 
B[0] := 42; 
Writeln(A[0]); 

Это выведет

0 
42 

Это потому, что после того, как B := A две переменные см в том же массиве.

Copy Используйте, чтобы создать новый массив, который является копией первого:

B := Copy(A); 
+0

Есть более общий метод, который я могу использовать, чтобы скопировать значение любого типа данных? – Justin

+0

Вы не можете написать функцию глубокой копии, которая может работать для произвольных типов данных. Но вы можете использовать расширенный RTTI, чтобы сделать глубокую копию для определенного класса типов. –

0

Объект является указательным типом. Некоторые указатели (копии объектов) могут обращаться к одной и той же части памяти, поэтому модификация одной копии влияет на другие.
У вас проблема не совсем определена, но я подозреваю, что вам может понадобиться «глубокая копия» содержимого объекта - например, с помощью Assign - наследовать класс от TPersistent и реализовать метод AssignTo.