Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.11.2012, 00:50   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию Правильная перегрузка методов класса.

Доброго времени суток!

Имеется класс-наследник THTTPSend, для него требуется реализовать 3 базовых метода: GET, POST, HEAD, однако только эти 3 мне показалось малым кол-во и нужно сделать ещё удобнее...
Код:
    function GET(sURL: string; out aStr: string): Boolean; overload;
    function GET(sURL: string; out sStream: TStream): Boolean; overload;

    function HEAD(sURL: string): Boolean; overload;
    function HEAD(sURL: string; out aStr: string): Boolean; overload;
    function HEAD(sURL: string; out sStream: TStream): Boolean; overload;

    function POST(sURL: string; sParams: string): Boolean; overload;
    function POST(sURL: string; sParams: TStrings): Boolean; overload;
    function POST(sURL: string; sParams: TStream): Boolean; overload;

    function POST(sURL: string; sParams: string; out sStr: string)
      : Boolean; overload;
    function POST(sURL: string; sParams: string; out sStream: TStream)
      : Boolean; overload;

    function POST(sURL: string; sParams: TStrings; out sStr: string)
      : Boolean; overload;
    function POST(sURL: string; sParams: TStrings; out sStream: TStream)
      : Boolean; overload;

    function POST(sURL: string; sParams: TStream; out sStr: string)
      : Boolean; overload;
    function POST(sURL: string; sParams: TStream; out sStream: TStream)
      : Boolean; overload;
При таком раскладе:
Код:
      0: // head
        begin
          if IsResponsibleReqChk.Checked then
          begin
            case AnswerTypeRGr.ItemIndex of
              0: // string
                begin
                  HTTP.HEAD(TargetEdit.Text, ResponseMemo.Text); //Ругается
                end;
              1: // stream
                begin
                  HTTP.HEAD(TargetEdit.Text, SS); //Ругается
                  ResponseMemo.Text := SS.DataString;
                end;
            end;

          end
          else
          begin
            HTTP.HEAD(TargetEdit.Text);
          end;
        end;
      1: // GET
        begin
          case AnswerTypeRGr.ItemIndex of
            0: // string
              begin
                HTTP.GET(TargetEdit.Text, ResponseMemo.Text); //Ругается
              end;
            1: // stream
              begin
                HTTP.GET(TargetEdit.Text, SS); //Ругается
                ResponseMemo.Text := SS.DataString;
              end;
          end;
        end;
    end;
Там где ругается, кроет матом():
Код:
[DCC Error] frmMain.pas(96): E2250 There is no overloaded version of 'HEAD' that can be called with these arguments
[DCC Error] frmMain.pas(100): E2250 There is no overloaded version of 'HEAD' that can be called with these arguments
[DCC Error] frmMain.pas(116): E2250 There is no overloaded version of 'GET' that can be called with these arguments
[DCC Error] frmMain.pas(120): E2250 There is no overloaded version of 'GET' that can be called with these arguments
Все методы класса - перегружены. В чем проблема? Все должно быть хорошо, но неок... почему так?
SS - TStream
Человек_Борща вне форума Ответить с цитированием
Старый 10.11.2012, 02:23   #2
spamer
Software Developer
Старожил
 
Аватар для spamer
 
Регистрация: 19.12.2008
Сообщений: 2,070
По умолчанию

Код:
HTTP.HEAD(TargetEdit.Text, ResponseMemo.Text);
HTTP.GET(TargetEdit.Text, SS);
вторым параметром в соответствующих описаниях функций идет out параметр, а свойство, в данном случае ResponseMemo.Text (SS - это тоже свойство?), не может быть передано в качестве out параметра - только переменная идентичного типа.
Будь проще и люди к тебе потянутся
spamer вне форума Ответить с цитированием
Старый 10.11.2012, 08:27   #3
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

ss - переменная TSTREAM.
А как тогда правильно сделать?

Суть в том, что это все функции с булевым результатом, и некоторые должны вернуть данные.

Может я вас не правильно понял?
Типы out параметров разные, я специально сделал так, чтобы в конечном итоге получившийся класс был очень юзабелен, без собственных приворотных заморочек. Я не знаю почему компилятор не может распознать ситуацию.
Код:
            case AnswerTypeRGr.ItemIndex of
              0: // string
                begin
                   //1-й параметр - ссылка, 2 параметр - строка, куда вернется результат в виде текста.
                   {TMemo.Text = type TCaption; 
                      TCaption = type string}
                   {Приведение типа к строке String(TMemo.text) - результата не дает}
                   HTTP.HEAD(TargetEdit.Text, ResponseMemo.Text); //Ругается
                end;
              1: // stream
                begin
                  //1-й параметр - ссылка, 2 параметр - TStream.
                  {В качестве второго параметра передается TStringStream, наследник TStream}
                  HTTP.HEAD(TargetEdit.Text, SS); //Ругается
                  ResponseMemo.Text := SS.DataString;
                end;
            end;

          end
          else
          begin
             //Тот только 1 параметр - строка с ссылкой. 
            HTTP.HEAD(TargetEdit.Text); //Не ругается...
          end;
Есть подозрение что это недоработка разработчиков т.к. у меня ситуация, что типы данных в перегруженных методах, в основном, разные, а вот имена переменных - везде одинаковые, по логике вещей, приоритет должен отдаваться кол-ву переменных и их типам, а имена переменных - фиг с ними.

Последний раз редактировалось Человек_Борща; 10.11.2012 в 13:30.
Человек_Борща вне форума Ответить с цитированием
Старый 10.11.2012, 13:42   #4
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,882
По умолчанию

Хм, ну сделать - то просто, в случае со строкой
Код:
0: // string
begin
s := ''; // s: string,  для надёжности её занилим
// а то может быть ав в случае если в ней будет мусор из стека
HTTP.HEAD(TargetEdit.Text, s);  
ResponseMemo.Text := s;
end;
C потоком хитрее, судя по out он у Вас в функции создаётся, но я бы советовал очень аккуратно относиться к написанию функций, возвращающих объект - утечка памяти по невнимательности - первое дело.
Лучше создать поток до вызова функции, передать его в функцию (модификатор параметра , вроде var out не нужен, лучше const или без модификатора даже), функция его заполняет, после окончания функции пользуемся потоком, и прибиваем его.
Булеан результаты функций тут не при чём, нет смысла их трогать.
phomm вне форума Ответить с цитированием
Старый 10.11.2012, 15:54   #5
spamer
Software Developer
Старожил
 
Аватар для spamer
 
Регистрация: 19.12.2008
Сообщений: 2,070
По умолчанию

Цитата:
Может я вас не правильно понял?
Скорее всего так. Все очень просто - 1) свойство, как таковое, вы не можете передать в качестве out параметра; 2) тип out параметра в объявлении функции и тип переменной, которая будет передаваться в эту функцию, должны совпадать.


Код:
    function HEAD(const URL: string): Boolean; overload;
    function HEAD(const URL: string; out Str: string): Boolean; overload;
    // Функция принимает стрим не как out параметр, поэтому переменную которую сюда предашь - может быть объявлена например как tmpStream: TMemoryStream //или др.
    // А вот если бы параметр был объявлен как out, то переменная должна обязательно быть объявлена как TStream.
    function HEAD(const URL: string; const Stream: TStream): Boolean; overload;

function TForm1.HEAD(const URL: string): Boolean;
begin
  ShowMessage(URL);
  Result := True;
end;

function TForm1.HEAD(const URL: string; out Str: string): Boolean;
begin
  Str := '';

  Str := 'new ' + URL;
  ShowMessage(URL);
  Result := True;
end;

function TForm1.HEAD(const URL: string; const Stream: TStream): Boolean;
begin
  ShowMessage(URL);
  Result := Stream <> nil;
  if not Result then
    Exit;
  // Пишем данные в стрим или еще что-то делаем
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  TestStr1, TestStr2, NewTestStr2, TestStr3: String;
  tmpStream: TStream; // либо как вариант: объявить поле класса, добавить свойство read-only и в функцию передать поле класса(переменную), но не свойство.
begin
  TestStr1 := 'test string 1';
  HEAD(TestStr1);
  TestStr2 := 'test string 2';
  HEAD(TestStr2, NewTestStr2);
  ShowMessage(NewTestStr2);
  tmpStream := TMemoryStream.Create;
  try
    TestStr3 := 'test string 3';
    HEAD(TestStr3, tmpStream);
    // Работает с данными из стрима
  finally
    // если переменная стрима - это поле класса, уалять в деструкторе
    FreeAndNil(tmpStream);
  end;
end;
Но как уже и сказал phomm, объектные переменные не стоит передавать в качестве out параметров (возможность эта применяется, но редко).
Цитата:
s := ''; // s: string, для надёжности её занилим
// а то может быть ав в случае если в ней будет мусор из стека
Не стоит этого делать в вызывающей функции. out параметрам значение должна назначать вызываемая функция. А вот с var параметрами уже наоборот, как вы и написали.
И еще, Человек_Борща, все таки старайся передавать все входные параметры как const, а не так как у тебя в примере - без модификатора...
Будь проще и люди к тебе потянутся

Последний раз редактировалось spamer; 10.11.2012 в 16:05.
spamer вне форума Ответить с цитированием
Старый 10.11.2012, 18:25   #6
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

phomm, spamer, смотрите
Есть методы:
Код:
    function GET(sURL: string; aResponseStr: string): Boolean; overload;
    function GET(sURL: string; sResponseStream: TStream): Boolean; overload;
Их реализация:
Код:
function THTTPSendEx.GET(sURL: string; sResponseStream: TStream): Boolean;
begin
  Result := HTTPMethod('GET', sURL);
  if (fGZUse = uAll) or (fGZUse = uOnlyToUs) then
    GZDecompressStream(inherited Document, sResponseStream)
  else
    sResponseStream.CopyFrom(inherited Document, inherited Document.Size);
end;

function THTTPSendEx.GET(sURL: string; aResponseStr: string): Boolean;
var
  SS: TStringStream;
begin
  Result := HTTPMethod('GET', sURL);
  SS := TStringStream.Create;
  try
    if (fGZUse = uAll) or (fGZUse = uOnlyToUs) then
      GZDecompressStream(inherited Document, SS)
    else
      SS.LoadFromStream(inherited Document);

    if fDEcodeUTF8 then
      aResponseStr := UTF8Decode(SS.DataString)
    else
      aResponseStr := SS.DataString;
  finally
    FreeAndNil(SS);
  end;
end;
Как правильно реализовать, чтобы результат возвращался в aResponseStr, sResponseStream?
Человек_Борща вне форума Ответить с цитированием
Старый 10.11.2012, 22:47   #7
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,882
По умолчанию

Цитата:
Сообщение от spamer Посмотреть сообщение
Код:
s := ''; // s: string,  для надёжности её занилим
// а то может быть ав в случае если в ней будет мусор из стека
Не стоит этого делать в вызывающей функции. out параметрам значение должна назначать вызываемая функция. А вот с var параметрами уже наоборот, как вы и написали.
Я подразумевал то, что по моему разумению происходит так:
передавая строку как вар или аут параметр, мы передаём указатель на строку, которая есть указатель на данные строки (ансистроки). Поскольку строка как переменная в подпрограмме локальная, то само значение переменной строки (указателя на данные строки) есть мусор со стека, передав этот мусор (или даже указатель на него) в другую подпрограмму, при попытке изменить данную строку для возврата результата, будет задействован автоматический механизм управления строками в дельфи, т.е. он из старого места (данные строки) попробует строку удалить, а для результата создаст новую строку (в куче) и указателю на строку присвоит адрес созданного блока памяти. Когда он попробует удалить строку по мусорной ссылке, то и может быть ав.
Поэтому я и указал, что заниливаем чтобы не было этого, у нилового указателя - переменной пустой строки он не будет пробовать удалить "старую" память.

Человек_Борща , я не знаю, как там в синапс ( я так понял Вы её используете), но один и тот же приём Result := HTTPMethod(...); для получения и строки и потока меня настораживает, советую сперва всё перепроверить, в том числе и по справке.

Последний раз редактировалось phomm; 10.11.2012 в 23:02.
phomm вне форума Ответить с цитированием
Старый 10.11.2012, 23:04   #8
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

У синапсов нет справки, только унылая техн. документация слизанная с исходников.
Я не пишу новый THTTPSend, я делаю навес над ним, расширяющий возможности.
HTTPMethod - единственный метод отправки данных.
Я меняю некоторые значения/устанавливаю новые, и вызываю стандартный HTTPMethod. Данные уходят/приходят нормально. Проблема с возвратом их куда-либо, не через результат функции(Функция возвращает успешность отправки данных вообще).
Человек_Борща вне форума Ответить с цитированием
Старый 10.11.2012, 23:27   #9
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,882
По умолчанию

Ах, всё, дошло.. просто меня что-то смутило это...
Пока предположу, что после работы с потоком на чтение (в обоих функциях Get, ибо в обоих работа с потоком) его надо на начало перематывать.

Последний раз редактировалось phomm; 10.11.2012 в 23:32.
phomm вне форума Ответить с цитированием
Старый 10.11.2012, 23:38   #10
spamer
Software Developer
Старожил
 
Аватар для spamer
 
Регистрация: 19.12.2008
Сообщений: 2,070
По умолчанию

Насчет очищать/не очищать out-var параметры - можно посмотреть вот тут ответы.
Как-то так:
Код:
  THTTPSendEx = class(THTTPSend)
  public
    function GET(const sURL: string; out aResponseStr: string): Boolean; overload;
    function GET(const sURL: string; const sResponseStream: TStream): Boolean; overload;
  end;

function THTTPSendEx.GET(const sURL: string; out aResponseStr: string): Boolean;
var
  SS: TStringStream;
begin
  aResponseStr := '';
  Result := HTTPMethod('GET', sURL);
  if not Result then
    Exit;
  SS := TStringStream.Create;
  try
    if (fGZUse = uAll) or (fGZUse = uOnlyToUs) then
      GZDecompressStream(Document, SS)
    else
      SS.LoadFromStream(Document);

    SS.Position := 0;
    if fDEcodeUTF8 then
      aResponseStr := UTF8Decode(SS.DataString)
    else
      aResponseStr := SS.DataString;
  finally
    FreeAndNil(SS);
  end;
end;

function THTTPSendEx.GET(const sURL: string; const sResponseStream: TStream): Boolean;
begin
  Result := sResponseStream <> nil;
  if not Result then
    Exit;
  sResponseStream.Size := 0;
  sResponseStream.Position := 0;
  try
    Result := HTTPMethod('GET', sURL);
    if not Result then
      Exit;
    if (fGZUse = uAll) or (fGZUse = uOnlyToUs) then
      GZDecompressStream(Document, sResponseStream)
    else
      sResponseStream.CopyFrom(Document, Document.Size);
    sResponseStream.Position := 0;
  except
    Result := False;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  h: THTTPSendEx;
  str: string;
  stream: TStream;
begin
  h := THTTPSendEx.Create;
  stream := TMemoryStream.Create;
  try
    h.GET('url', str);
    h.GET('url', stream);
  finally
    FreeAndNil(h);
    FreeAndNil(stream);
  end;
end;
Будь проще и люди к тебе потянутся
spamer вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
перегрузка методов класса (с++) Antej Общие вопросы C/C++ 2 24.07.2012 17:58
Перегрузка виртуальных методов mongolores Общие вопросы Delphi 27 14.05.2012 19:12
Ошибка в использовании методов класса Jugger Общие вопросы C/C++ 2 26.10.2011 01:29
Вектор из callback'ов методов класса Gongled Общие вопросы C/C++ 7 05.01.2011 16:29
массив методов класса DartDayring Общие вопросы C/C++ 0 07.12.2010 20:00