Не получается унаследоваться от интерфейса

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Не получается унаследоваться от интерфейса

Сообщение xterro » 15.04.2019 09:57:23

Доброго времени суток, сделал класс, пытаюсь унаследовать его от интерфейса(TR_IDrawable), но при компиляции чего-то ругается :(

Код: Выделить всё
unit Prim;
{$mode objfpc}{$H+}
interface
uses
    Classes, SysUtils, Graphics, GeomUtils, TR_ColorInterface, TR_DrawableInterface;

type
    TPrimitive = class(TR_IDrawable)
    private
        FPoints         : array of TPointF;
        FNPoints        : Integer;
        FColor          : TR_IColor;
        FThickness      : Integer;
        FDashSize       : Integer;
        FDashSpace      : Integer;
    public
        constructor Create;
        procedure Draw(); virtual; abstract;
        function  GetBBox() : TRectF; virtual; abstract;
    end;

////////////////////////////////////////////////////////////////////////////////
implementation

    constructor TPrimitive.Create();
    begin
        FNPoints    := 0;
        FThickness  := 1;
        FDashSize   := 1;
        FDashSpace  := 1;
    end;

end.                                                 


интерфейс от которого наследуюсь:

Код: Выделить всё
unit TR_DrawableInterface;

{$mode objfpc}{$H+}

interface

uses
    Classes, SysUtils, GeomUtils;

type
    TR_IDrawable = interface
        procedure Draw();
        function  GetBBox() : TRectF;
    end;

implementation
end.                                         


Сообщение при компиляции:

tr_drawableinterface.pas(8,35) Hint: Unit "TR_GraphicInterface" not used in TR_DrawableInterface
prim.pas(12,18) Error: No matching implementation for interface method "IUnknown.QueryInterface(constref TGuid,out <Formal type>):LongInt; StdCall;" found
prim.pas(12,18) Error: No matching implementation for interface method "IUnknown._AddRef:LongInt; StdCall;" found
prim.pas(12,18) Error: No matching implementation for interface method "IUnknown._Release:LongInt; StdCall;" found
prim.pas(29,1) Fatal: There were 3 errors compiling module, stopping

Что за IUnknown.QueryInterface().... Откуда взялось? :shock:

Сразу спрошу, чтобы мне сделать абстрактный класс, достаточно просто один из его методов сделать абстрактным? Зачем мне у такого класса имплементировать конструктор (без этого ругается)
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Не получается унаследоваться от интерфейса

Сообщение Дож » 15.04.2019 10:07:32

Это три функции, которые есть в любом интерфейсе и должны быть реализованы в классе. Стандартная их реализация есть в TInterfacedObject
Код: Выделить всё
type
    TPrimitive = class(TInterfacedObject, TR_IDrawable)
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Не получается унаследоваться от интерфейса

Сообщение xterro » 15.04.2019 10:48:46

А зачем они вообще нужны, без этого не обойтись? У меня своя "маленькая экосистема" интерфейсов, получается что я привязываюсь... а к чему я собственно привязываюсь? :?
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Не получается унаследоваться от интерфейса

Сообщение iskander » 15.04.2019 10:57:09

Попробуйте объявить интерфейс так:
Код: Выделить всё
type
    {$INTERFACES CORBA}
    TR_IDrawable = interface
        procedure Draw();
        function  GetBBox() : TRectF;
    end;   
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Не получается унаследоваться от интерфейса

Сообщение xterro » 15.04.2019 11:15:37

Можно ещё вопрос, когда мы объявляем интерфейс, параметры функций и процедур интерфейса можно пропускать? Т.е объявили скажем функцию Line() в интерефейс, а список параметров оставляем пустым, а в производном классе уже при переопределении указываем Line(x1, y1, x2, y2) - это допустимо или в интерефейсе параметры тоже обязательно объявлять?
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Не получается унаследоваться от интерфейса

Сообщение iskander » 15.04.2019 11:36:05

xterro писал(а):когда мы объявляем интерфейс, параметры функций и процедур интерфейса можно пропускать?

Прототипы должны быть объявлены полностью.
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Не получается унаследоваться от интерфейса

Сообщение xterro » 15.04.2019 12:49:11

Спасибо )

Добавлено спустя 27 минут 27 секунд:
Можно ещё вопрос? Реализую интерфейс

Код: Выделить всё
TR_IColor = interface

        function Red() : byte;
        function Green() : byte;
        function Blue() : byte;

        function RGBToColor(R, G, B: Byte): TR_IColor;
    end;                                                     


реализация

Код: Выделить всё
CanvasColor = class(TInterfacedObject, TR_IColor)
    private
        color : TColor;
    public
        constructor Create;
        function Red() : byte;
        function Green() : byte;
        function Blue() : byte;

        function RGBToColor(R, G, B: Byte): CanvasColor;

implementation

    constructor CanvasColor.Create;
    begin

    end;

    function CanvasColor.Red() : byte;
    begin

    end;

    function CanvasColor.RGBToColor(R, G, B: Byte): CanvasColor;
    begin
        Result := nil;
    end;                                                               

    end;                                                     


а он мне ругается:

TR_CanvasColor.pas(11,19) Error: No matching implementation for interface method "TR_IColor.RGBToColor(Byte,Byte,Byte):TR_IColor;" found


мне возвращать из функции TColor или мой тип CanvasColor ? Ругается и с тем и с другим :shock:


Кажется разобрался - не правильно использую тип и функцию как таковую. Ведь мой объект и так хранит цвет, не смысла что-то возвращать )
Последний раз редактировалось xterro 15.04.2019 13:55:08, всего редактировалось 1 раз.
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Не получается унаследоваться от интерфейса

Сообщение iskander » 15.04.2019 13:54:51

У вас типы возвращаемого значения в объявлении и реализации не совпадают:
Код: Выделить всё
TR_IColor = interface
       .....
       function RGBToColor(R, G, B: Byte): TR_IColor;
    end;

и
Код: Выделить всё
  CanvasColor = class(TInterfacedObject, TR_IColor)
        .....
        function RGBToColor(R, G, B: Byte): CanvasColor;
  end;
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Не получается унаследоваться от интерфейса

Сообщение xterro » 15.04.2019 13:58:15

Это у меня интерфейс общего типа, и отдельно его реализация в зависимости от подсистемы. Грубо говоря, будет два класса, унаследованы от этого интерфейса, при инициализации программы, будет передаваться тот или иной класс реализации, в зависимости от того что доступно. Скажем, если я буду рисовать в контексте OpenGL, то будет класс GLColor, а если рисую на TCanvas, то CanvasColor.
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Не получается унаследоваться от интерфейса

Сообщение iskander » 15.04.2019 14:08:41

Компилятору по барабану где и как вы будете рисовать.
Типы возвращаемого значения в объявлении интерфейса и его реализации должны совпадать.
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Не получается унаследоваться от интерфейса

Сообщение xterro » 15.04.2019 16:44:47

Тогда я не понимаю, как в FPC можно реализовать концепцию отделения интерфейса от реализации :( Поясню:

Сделал интерфейс TR_IColor, сделал его реализацию
Код: Выделить всё
TR_IColor = interface
    ...
end;                 


Код: Выделить всё
CanvasColor = class(TInterfacedObject, TR_IColor)
    ...
end;                                   


Далее у меня есть класс, который наследуется от своего интерфейса, но в зависимости от реализации должен возвращать тот или иной тип объекта, описанные одним интерфейсом

Код: Выделить всё
TR_IGraphicContext = interface
        function GetColor() : TR_IColor;       // тут на момент объявления интерфейса я не знаю какой тип будет возвращен, да и не важно это сейчас
        procedure SetColor(c : TR_IColor);

        procedure Line(X1 : Integer; Y1 : Integer; X2 : Integer; Y2 : Integer);
        procedure Rectangle(X1 : Integer; Y1 : Integer; X2 : Integer; Y2 : Integer);

    end;                                             


далее реализация этого интерфейса:

Код: Выделить всё
TR_CanvasContext = class(TInterfacedObject, TR_IGraphicContext)
    private
        FCanvas : TCanvas;
        FColor :  CanvasColor;
    public
        function GetColor() : CanvasColor;       
        procedure SetColor(c : CanvasColor);

        procedure Line(X1 : Integer; Y1 : Integer; X2 : Integer; Y2 : Integer);
        procedure Rectangle(X1 : Integer; Y1 : Integer; X2 : Integer; Y2 : Integer);
    end;

implementation

function TR_CanvasContext.GetColor() : CanvasColor;
begin
    Result := FColor;
end;

procedure TR_CanvasContext.SetColor(c : CanvasColor);
begin
    FColor := c;
end;                                                                   


Здесь ругается на CanvasColor, мол не соответствует интерфейсу
TR_CanvasContextImpl.pas(11,24) Error: No matching implementation for interface method "TR_IGraphicContext.GetColor:TR_IColor;" found


Хорошо, но как тогда мне обыграть всё это дело? Например, создам я ещё одну реализацию интерфейса TR_IGraphicContext, назовем его скажем TR_GLContex, а в нем мне надо будет другую реализацию цвета, какую-нибудь CMYKColor, но тоже порожденную от одного интерфейса TR_IColor (пример утрированный), и чего делать? :? Интерфейс же один, насколько знаю, в языках, скажем java или C# так можно делать (скажем объявили что тип параметра у нас интерфейс или абстрактный класс, а передаём в качестве значения параметра реализацию этого интерфейса или наследника абстрактного класса), а тут чет затык у меня. Может сумбурно объяснил (


UPD: Кажется разобрался - нужно явно приводить тип;

Код: Выделить всё
procedure TR_CanvasContext.SetColor(c : TR_IColor);
begin
    FColor := c as CanvasColor;   // без "as CanvasColor" не работает
end; 
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Не получается унаследоваться от интерфейса

Сообщение Mirage » 15.04.2019 23:39:00

Цвет это что? Тройка RGB. Может еще A. Во всех случаях. Прекрасно хранится в 32-битном слове. Ну или как запись из 4-х Single, если точность такая прям нужна. Лучше такой тип и использовать. А уже по месту использования преобразовывать во что надо. А то вся эта возня с интерфейсами небыстрая, для такой базовой вещи как цвет.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Не получается унаследоваться от интерфейса

Сообщение xterro » 16.04.2019 08:24:27

Mirage писал(а):Цвет это что?

При использования родного TCanvas это обертка над TColor, а если буду использовать скажем OpenGL, то да, придётся наверно использовать dword для хранения цвета... Хотя, сейчас подумал, можно наверно сделать его универсальней, хранить цвет в dword, для класса цвета наверно действительно нет смысла городить огород. Буду дальше пробовать 8)
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 23

Рейтинг@Mail.ru