Parduz
Parduz

Reputation: 594

Need help converting Graphics32 Delphi sample to C++

USING BDS2006: I'm trying to convert the Graphics32 Resampler_ex example in C++, but i can't even understand what happens in some codes, or how to rewrite that code in C++.

In that sample there's a combobox to choose what resampler to use: This is the Deplhi code in his OnChange event:

procedure TfmResamplersExample.KernelClassNamesListClick(Sender: TObject);
var
  Index: Integer;
begin
  Index := KernelClassNamesList.ItemIndex;
  if Src.Resampler is TKernelResampler then
    with TKernelResampler(Src.Resampler) do
    begin
      Kernel := TCustomKernelClass(KernelList[Index]).Create;
      LbParameter.Visible := (Kernel is TAlbrechtKernel) or
{$IFDEF Ex}
        (Kernel is TGaussianKernel) or
        (Kernel is TKaiserBesselKernel) or
        (Kernel is TNutallKernel) or
        (Kernel is TBurgessKernel) or
        (Kernel is TBlackmanHarrisKernel) or
        (Kernel is TLawreyKernel) or
{$ENDIF}
        (Kernel is TSinshKernel);
      gbParameter.Visible := LbParameter.Visible;
      SetKernelParameter(Kernel);
      CurveImage.Repaint;
    end;
end;

where:

{ TClassList }
{ This is a class that maintains a list of classes. }
TClassList = class(TList)
protected
  function GetItems(Index: Integer): TClass;
  procedure SetItems(Index: Integer; AClass: TClass);
public
  function Add(AClass: TClass): Integer;
  function Extract(Item: TClass): TClass;
  function Remove(AClass: TClass): Integer;
  function IndexOf(AClass: TClass): Integer;
  function First: TClass;
  function Last: TClass;
  function Find(AClassName: string): TClass;
  procedure GetClassNames(Strings: TStrings);
  procedure Insert(Index: Integer; AClass: TClass);
  property Items[Index: Integer]: TClass read GetItems write SetItems; default;
end;
ResamplerList: TClassList;

My problems are on this line

      Kernel := TCustomKernelClass(KernelList[Index]).Create;

How can i convert this line in C++?

EDIT AFTER THE COMMENTS AND THE ANWERS:

Ok, seems beyond my undertanding. For my purposes, it will suffice to be able to replicate what this code do without too much hassle.

Could it be possible to instantiate the right class just using a switch based on the itemindex?

These are the 4 classes i should instantiate:

class DELPHICLASS TNearestResampler;
class PASCALIMPLEMENTATION TNearestResampler : public Gr32::TCustomResampler 
{
    typedef Gr32::TCustomResampler inherited;
    [...]
}

class DELPHICLASS TLinearResampler;
class PASCALIMPLEMENTATION TLinearResampler : public Gr32::TCustomResampler 
{
    typedef Gr32::TCustomResampler inherited;
    [...]
};


class DELPHICLASS TDraftResampler;
class PASCALIMPLEMENTATION TDraftResampler : public TLinearResampler 
{
    typedef TLinearResampler inherited;
    [...]   
};


class DELPHICLASS TKernelResampler;
class PASCALIMPLEMENTATION TKernelResampler : public Gr32::TCustomResampler 
{
    typedef Gr32::TCustomResampler inherited;
    [...]
};

I don't ever get how could i assign one of them to "Kernel"....

Upvotes: 1

Views: 419

Answers (2)

David Heffernan
David Heffernan

Reputation: 613013

The Delphi code relies on Delphi virtual constructors. This functionality does not exist in C++.

If you wanted to translate the code literally then you'd need to find a way to instantiate the class by calling the virtual Delphi constructor. You cannot do that in C++ so you'd need some Delphi code to glue it all together. Remy's answer here shows how to use __classid() to obtain a Delphi metaclass. You'd then need to pass that metaclass to a Delphi function to perform the instantiation.

Frankly I would view that as being a rather convoluted solution to the problem. Instead I think I'd replace the class list with a function list. The functions in the list would have the task of instantiating a new instance of a kernel. So instead of adding a class to the list, you add a function that creates a new instance of the class. In fact you might want a map between name and function, it all depends on your needs.

Upvotes: 1

Spook
Spook

Reputation: 25927

From what I remember from Delphi programming, this will actually instantiate the same type of class, which currently is kept in KernelList[index] and then cast it back to TCustomKernelClass. AFAIK there is no such mechanism in C++, but you can solve it by introducing virtual CreateInstance method:

class TCustomKernelClass
{
public:
    virtual TCustomKernelClass * CreateInstance() = 0;
}

class TDerivedKernelClass
{
public:
    TCustomKernelClass * CreateInstance()
    {
        return new TDerivedKernelClass();
    }
}

You'll have to introduce some changes in the classes though. I doubt it can be solved directly in C++.


Edit: In response to comments

Ok, I see now, there are class definitions kept in that list. Since RTTI in C++ is not as extensive as in Delphi, I'd change the code to (written from memory, may not compile):

std::vector<std::function<TBaseKernelClass(void)>> KernelList;

KernelList.push_back([]() { return new TDerivedKernelClass(); });

// (...)

Kernel = KernelList[index]();

Upvotes: 0

Related Questions