Задача: написать программу, которая будет иметь 3 основных класса для работы, которые реализую в свою очередь весь функционал программы: лист задач, управляющий класс задачи, класс выделения потоков для решения задачи.

Этот проект является реальным и может быть применен вами в решении своих задач. Тут мы не будем поднимать тему интерфейсов, мы рассмотрим нестандартное решение данной задачи, которое уложится в 2 или 3 юнита. Все зависит только от того, как вам удобнее.

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

Приведем краткое описание классов:
TContolTask - лист задач
TChecker - выполнение задачи
TThreadChecker - потоки для задачи

Опишем стандартно классы:
Как вас ранее учили: каждый класс в своем юните.
unit ContolTask ;
unit Checker;
unit ThreadChecker;

Ну что ж, давайте быстро опишем классы:

Код:
type
  TContolTask = class (TObject)
    public
     constructor Create; virtual;
    strict private
     Workers: array[1..10] of TChecker;
     destructor Destroy; virtual;
  end;
Код:
type
  TChecker = class (TObject)
    public

    private
     Work: Boolean;
     ThreadCkecker: TThreadChecker;
     constructor Create(link: WideString); virtual;
     destructor Destroy;  virtual;

    protected

  end;
Код:
type
  TThreadChecker = class (TChecker)
  public

  private
   procedure Execute;
   constructor Create(link: WideString); override;
   destructor Destroy;  override;
  protected

  end;
В юнит с чекером мы подключаем юнит с классом потоков и наоборот, чтобы мы могли ссылаться друг на друга, а также наследуем класс (!_это_вынужденная_ошибка), чтобы иметь доступ к Work. Из этого всего мы получим ошибку: F2047 Circular unit reference to , что и требовалось доказать. Мы попали в круговые ссылки и при разных вариантах компиляции у нас ошибки могут отличаться. Вторая ошибка, которая может возникнуть - это Out of memory, что также свидетельствует, что компилятор задыхается от того, что у нас 2 юнита ссылаются друг на друга. В данном случае решением будет использование интерфейсов. Это решение было многократно описано в Интернете, и оно нам не интересно. Я предлагаю поступить иначе и решить задачу не таким популярным способом, как вложенные класс.

Вложенный класс представляет из себя класс в классе, а именно:
Код:
type Cl1 = class(TObject)
  public

   Work: Bool;
   type Cl2 = class(TObject)
   public
     procedure A;
   private

    protected

   end;
  private
   TCL: Cl2;
  protected

end;
В данном примере показано как правильно вложить класс 2 в класс 1. В данном случае мы еще не будем иметь доступ к переменной Work из вложенного класса, так как данная переменная принадлежит конкретному экземпляру класса, а не классу. Пример ошибки: [dcc32 Error] Unit1.pas(52): E2124 Instance member 'Work' inaccessible here

1612452297592.png

Как мы видим, мы не можем обращаться таким образом. Исправить это можно следующем образом: мы определяем данную переменную не как экземпляр класса, а как принадлежащую классу class var Work: bool;. Теперь мы можем собрать проект.

Полный листинг примера:
Код:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type Cl1 = class(TObject)
  public

   class var Work: Boolean;
   // Work: Boolean;
   type Cl2 = class(TObject)
   public
     procedure A;
   private

    protected

   end;
  private
   TCL: Cl2;
  protected

end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

{ Cl1.Cl2 }

procedure Cl1.Cl2.A;
begin
while Work do
begin

end;

end;

end.
Перенесем данный пример на реальную задачу и получим следующую картину:
Код:
type
  TChecker = class (TObject)
   public
    class var baseFile: file;
    class var ThreadWork: Boolean;
    type TThreadChecker = class(TThread)
      strict private
       function CheckRegExpr(line :string): Boolean;
       function GetCheckedLine(line: string): string;
       procedure CheckLinsDB(out base: TStringList);
       procedure AddLinsDB(out base: TStringList);
       procedure Execute;
       destructor Destroy; override;
      protected

      public

      published
       constructor Create(link: WideString); virtual;
      end;
    type TStats = class
       strict private

       protected
        _iPrivateList, _iPublicList: Int64;
        _GoodLine, _BadLine, _NextLine, _MaxLine, _ProgressLine: Int64;
        _CountDataBase: Int64;
       public
        property CountDataBase: Int64 read _CountDataBase write _CountDataBase;
        property GoodLine: Int64 read _GoodLine write _GoodLine;
        property BadLine: Int64 read _BadLine write _BadLine;
        property NextLine: Int64 read _NextLine write _NextLine;
        property MaxLine: Int64 read _MaxLine write _MaxLine;
        property ProgressLine: Int64 read _ProgressLine write _ProgressLine;
        property iPrivateList: Int64 read _iPrivateList write _iPrivateList;
        property iPublicList: Int64 read _iPublicList write _iPublicList;
       published
        constructor Create;
     end;
    strict private
     baseLink: string;
     iBase: Integer;
     ThreadChecker: TThreadChecker;
     Stats: TStats;
     destructor Destroy; virtual;
     procedure Execute;
    protected

    published
     constructor Create(link: WideString); virtual;
  end;

Вам остается лишь расставить права доступа. Теперь наши потоки могут ссылаться на родительский класс и его переменные для дальнейшего выполнения работы. В классе задач вы создаете экземпляр класса и дописываете управление.

P.S. Хочу сразу сказать для любителей использовать синхронизацию в потоках: в данном примере НЕ ДОЛЖНО быть никакого общения с VCL потоком путем вызова стандартной функции синхронизации. Вы должны использовать класс статистики от родителя и передавать любые значения через критическую секцию. Вывод осуществлять через поток VCL (опрашивать вложенный класс статистики через менеджер задач).


Тема открыта для предложений и критики.