Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Приведение типов


Автор: Kbl4AH 20.1.2009, 14:48
Здравствуйте.
Код

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  I: Integer;
  O1, O2: TObject;
begin
  S := '123';
  I := 55;
  O1 := TObject(S);
  O2 := TObject(I);
  ShowMessage(string(O1));            // 1
  ShowMessage(string(O2));            // 2
  ShowMessage(string(Integer(O2)));   // 3
  ShowMessage(IntToStr(Integer(O2))); // 4
end;

Почему 2-я строка не работает, хотя 1-я - работает?
Почему 3-я строка не работает, хотя 4-я - работает?
 smile 
И почему 
Код

IntToStr(Integer(O1)) <> IntToStr(S)
?

Автор: Alexeis 20.1.2009, 15:13
Есть 2 понятия приведение типов и преобразование типов.

1) Например если юникодной строке присвоить анси строку, то выполниться преобразование типов. Создастся новая строка и символы будут преобразованы. Преобразование типов возможно только если есть функция преобразования (встроенная или нет).

2) Есть приведение типов. Приведение лишь говорит компилятору, что указанную область памяти нужно считать указанного типа. Например указатель можно преобразовать к LongInt, поскольку они одного размера. Но даже не смотря на это компилятор может накладывать ограничения на преобразования типов по смысловым соображениям. Делается это для того чтобы избежать ошибки при написании кода.

  Преобразование типов не следует использовать, кроме как в простейших случаях.

Добавлено через 4 минуты и 18 секунд
ShowMessage(string(O1)); - привет к краху программы, потому что типы несовместимы.

Добавлено через 8 минут и 24 секунды
  Хотя если быть точным O1 := TObject(S); уже ошибка. Когда умрет программа это уже вопрос вероятности.

Автор: Alexeis 20.1.2009, 15:40
Рассмотрим код
Код

procedure TForm1.FormCreate(Sender: TObject);
var
  S1 : AnsiString;
  S2 : WideString;

  p  : Pointer;
  c  : LongInt;
begin
  SetLength(S1, 20);
  S1[5] := 'g';
  S2 := WideString(S1);

  GetMem(p, 20);
  c := LongInt(p);

end;


и то что происходит на самом деле
1) я часть присвоение строк.
Код

Unit1.pas.35: S2 := WideString(S1);
00454217 8D45F4           lea eax,[ebp-$0c]
0045421A 8B55F8           mov edx,[ebp-$08]
0045421D E8160FFBFF       call @WStrFromLStr

Команды lea eax,[ebp-$0c] и  mov edx,[ebp-$08] передают аргументы в функцию WStrFromLStr, после чего происходит ее вызов 
call @WStrFromLStr
В данном случае функция преобразования строк WStrFromLStr системная

Второй пример
Код

Unit1.pas.38: c := LongInt(p);
0045422F 8B45F0           mov eax,[ebp-$10]
00454232 8945EC           mov [ebp-$14],eax


Загрузили значение адреса указателя в регистр eax mov eax,[ebp-$10], затем mov [ebp-$14],eax, записали эту величину в переменную типа LongInt. 
  Это пример преобразования приведения типов одного размера. 

Внешне оба примера неотличимы, но чтобы знать что реально происходит нужно владеть языком.
Во всех ваших примерах нет ни одного правильного преобразования, поскольку их просто не существует.

В С++ преобразование типа также неотличимо от вызова конструктора. В Delphi начиная с версии 2007 также введена система преобразования типов для классов и записей. 

Автор: Kbl4AH 20.1.2009, 15:51
Мдя smile 
Хорошо, тогда по-другому...
Мне нужна весчь типа TObject, которая могла бы хранить набор символов или число... И чтобы каким-то образом из этой весчи хранимую информацию можно было получить...
Как этого достичь?

Автор: MetalFan 20.1.2009, 16:02
Цитата(Kbl4AH @  20.1.2009,  15:51 Найти цитируемый пост)
Как этого достичь?

написать класс, который будет в себе хранить "набор символов или число"

Автор: Kbl4AH 20.1.2009, 16:14
Цитата(MetalFan @  20.1.2009,  16:02 Найти цитируемый пост)
написать класс, который будет в себе хранить "набор символов или число"

А можно smile ?

Автор: MetalFan 20.1.2009, 16:33
object pascal совсем не изучали?
да хоть както так:
Код

TDataObject = class( TObject )
private
  FString: string;
  FInt: integer;
public 
  property StringData: string read FString write FString;
  property IntegerData: integer read FInt write FInt;
end;


Автор: Kbl4AH 20.1.2009, 16:40
Цитата(MetalFan @  20.1.2009,  16:33 Найти цитируемый пост)
object pascal совсем не изучали?

Вы заставляете меня краснеть smile 

Автор: Kbl4AH 20.1.2009, 20:19
Что-то у меня ничего не работает((( В чем же дело?
Код

  TAObject = class(TObject)
  private
    FValue: string;
  public
    property Value: string read FValue write FValue;
  end;

var
  Form1: TForm1;
  AObject: TAObject;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  AObject := TAObject.Create;
  for I := 0 to Memo1.Lines.Count - 1 do
    begin
      AObject.Value := IntToStr(I);
      Memo1.Lines.Objects[I] := AObject;
    end;
  for I := 0 to Memo1.Lines.Count - 1 do
    Caption := Caption + ' ' + (Memo1.Lines.Objects[I] as TAObject).Value;
end;

end.

Автор: bems 21.1.2009, 19:42
ты создал только один объект. В результате (Memo1.Lines.Objects[I] as TAObject).Value это одно и то же для любого I
Или передвинь создание объекта внутрь цикла, или и правда тут можно обойтись простым приведением:
Код

Memo1.Lines.Objects[I] := TObject(I)

Автор: Kbl4AH 21.1.2009, 23:05
Дело не в этом... я даже одно и тоже значение не могу прочесть(((

Автор: THandle 22.1.2009, 00:03
Kbl4AH, Momo не поддерживает объекты. Посмотри тему:

http://www.delphikingdom.com/asp/answer.asp?IDAnswer=66586

В докозательство от меня попробуй вот эти два кода(в первом случае ListBox, во втором Memo):


Сам класс:
Код


  TAObject = class(TObject)
  private
    FValue: string;
  public
    constructor Create(const AValue: String);
    property Value: string read FValue write FValue;
  end;

...

constructor TAObject.Create(const AValue: String);
begin
  FValue := AValue;
end;


ListBox:

Код


procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to ListBox1.Items.Count - 1 do
      ListBox1.Items.Objects[I] := TAObject.Create(IntToStr(I));
  for I := 0 to ListBox1.Items.Count - 1 do
    Caption := Caption + ' ' + (ListBox1.Items.Objects[I] as TAObject).Value;
end;





Memo:

Код

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to Memo1.Lines.Count - 1 do
      Memo1.Lines.Objects[I] := TAObject.Create(IntToStr(I));
  for I := 0 to Memo1.Lines.Count - 1 do
    Caption := Caption + ' ' + (Memo1.Lines.Objects[I] as TAObject).Value;
end;



Memo и ListBox Должны быть заполнены естественно smile

Автор: Kbl4AH 22.1.2009, 10:06
Ответы в ссылке прочитал...
Так не честно smile Я ж про мему такое не знал...
Зато теперь узнал smile 
Действительно, пример с мемо выдает ошибку, а с листбоксом работает как надо.
И все-таки, в данном случае можно использовать приведение типов или лучше этого не делать и использовать класс?

THandle, Alexeis, MetalFan, bems, спасибо!

Автор: Alexeis 22.1.2009, 10:33
Цитата(Kbl4AH @  22.1.2009,  09:06 Найти цитируемый пост)
Я ж про мему такое не знал...

  Это не мема виновата, это тянется от предка TStrings и есть во всех его потомках.

Если что операция (Memo1.Lines.Objects[I] as TAObject).Value довольно медленная, но безопасная, в плане того что ничего ни где не затрешь.
оператор as при каждом обращении будет производить проверку RTTI с тем чтобы удостовериться действительно указанный объект имеет тип TAObject, если нет, то он будет проверять всех его предков, если не найдет ни одного соответствующего предка то вернет nil и гарантированно произойдет при первом же обращении AV.

Автор: THandle 22.1.2009, 18:03
Kbl4AH, твой случай(кстати зачем тут два цикла? можно и в один загнать)

Код

TAObject = class(TObject)
  private
    FValue: string;
  public
    constructor Create(const AValue: String);
    property Value: string read FValue write FValue;
  end;

...

constructor TAObject.Create(const AValue: String);
begin
  Inherited Create;
  FValue := AValue;
end;



Код

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to ListBox1.Items.Count - 1 do
    ListBox1.Items.Objects[I] := TAObject.Create(IntToStr(I));
  for I := 0 to ListBox1.Items.Count - 1 do
    Caption := Caption + ' ' + (ListBox1.Items.Objects[I] as TAObject).Value;
end;


Еще посмотри, может будет интересно:

http://delphist.ru/privedenie-tipov/

Добавлено через 53 секунды
Цитата(Alexeis @  22.1.2009,  10:33 Найти цитируемый пост)
nil и гарантированно произойдет при первом же обращении AV. 


Поэтому придумали еще и is smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)