Solved

Passing parameters to a class

Posted on 2004-09-01
14
220 Views
Last Modified: 2010-04-05
I have a class that i made a while back and would like to adapt it so i can use it without always having to make changes to it.  The main sticking point is that it deals with files of records which i'd like to move outside of the class and be able to define the record structure in any other unit and pass the parameters to the class.

example:

In my class i have this defined:

type
    TRecordName = packed record
    {...record structure}
end;

type
    TClassName = class

    private

       X : File of TRecordName;
       Y : TRecordName;
       {...rest of class functions and procedures that work with X and Y}

end;

What i'd like to do is be able to define the TRecordName in any unit i want and pass the structure to the class so it can still do what it was designed to do with the file of records - that way it allows the class to be "independant" in that it can be used on any record structure i define.

Anyone got a way to do this?
0
Comment
Question by:winuser2000
  • 6
  • 6
  • 2
14 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11961472
Apparantly you seem to want Macro functionaality, just like C++ and Assembler are offering. Unfortunately Delphi doesn't support this.

The best way to make a generic class is by using very generic code. If you're working with classes, consider the use of interfaces to include more abstraction in your code. If you want to stick to records then you need untyped variables, but except for the Variant record there's just no way to do this. (Delphi does support untyped parameters in functions, though!) Best way to solve this then would be this:

type
    TClassName = class
    private
       X : File;
       Y : Pointer;
       RecordSize:Word;

Y would then be pointing to a record somewhere in memory. This record would be RecordSize bytes in size, which you can set by using SizeOf(TRecordName). When reading from/writing to the file you'd have to use BlockRead and BlockWrite but that should not be too big of a problem.
Furthermore, be aware that records that you write to disk can't contain pointers. And the standard string in Delphi is a pointer. (The shortstring isn't, though.)

But actually, Delphi already has a nice, generic filereader/writer type. It's called TFileStream and is part of the TStream collection in Delphi... And streams can work with any kind of data.
0
 

Author Comment

by:winuser2000
ID: 11961841
"Apparantly you seem to want Macro functionaality, just like C++ and Assembler are offering"

Sheesh, i hope not because i have no idea what it is.

What i was basically looking for was a way to seperate the record structure from the actual unit.

For example, i can define the record structure in another unit and everything works perfectly if i put the unit name in the uses clause of the implementation section (to avoid circular problems).  I just thought that i since the file structure is in another unit and all works, maybe i could just pass the structure to the class in the constructor section (pooer example: such as MyRec.Create(TRecordStructure))

Not possible?
0
 
LVL 7

Expert Comment

by:LRHGuy
ID: 11962366
I don't know how important the actual structure of the record is, but you could do something like this to handle a file of records of any length:

type
tMyClass=class
  constructor create(aRecordLen:integer);
  destructor destroy;
  procedure readrec;
private
  fRecLen:integer;
  fRec:pointer;
  fFile:file;
end;

constructor tMyClass.create(arecordLen:integer);
begin
  assign(fFile,'datafile.dat');
  reset(fFile,aRecordLen);
  getmem(fRec,aRecordLen);
  fRecLen:=aRecordLen;
end;

destructor tMyClass.destroy;
begin
  closefile(fFile);
  freemem(fRec,fRecLen);
end;

procedure tMyClass.readrec;
begin
  { load next record }
  blockread(fFile,fRec^,1);
end;


Pass the record length to the class. You may want to pass the file name, too.

You might be able to work it into a generic solution.
0
 

Author Comment

by:winuser2000
ID: 11963346
ok, i made some changes using the ideas given and now i am trying to get the record data into Y - but am having trouble:

Example:

Declared in Unit 1
=============

type
   TRecordName = packed record
   {...record structure}
end;

type
   TClassName = class
        constructor create;
        destructor destroy; override;

   private

      X : File;
      Y : Pointer;
      Procedure Add(ABC : TRecordName);
      {...rest of class functions and procedures that work with X and Y}

end;

The problem is, how do i make Y equal to the ABC content so i can work with it?
0
 

Author Comment

by:winuser2000
ID: 11963417
forgot...

after

type
  TRecordName = packed record
  {...record structure}
end;

the rest is declared in unit 2
0
 
LVL 7

Expert Comment

by:LRHGuy
ID: 11963420
Try

with TRecordName(Y^) do ...

0
 
LVL 7

Expert Comment

by:LRHGuy
ID: 11963450
Oops, try:


procedure Add(abc:trecord);
begin
  Y^:=ABC;
end;

0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:winuser2000
ID: 11963461
but if i pass ABC which is a record in the ADD procedure, how do i get the contents of ABC into Y in the first place?

0
 
LVL 7

Expert Comment

by:LRHGuy
ID: 11963477
You could make the add routine not need to know the record structure, assuming the class knows the record length:

Procedure Add(var aData);
begin
  move(aData,Y^,fRecLen);
end;

0
 

Author Comment

by:winuser2000
ID: 11963483
tried that and got "operator not applicible to this operand" error
0
 
LVL 7

Accepted Solution

by:
LRHGuy earned 250 total points
ID: 11963548
Where did the error point? I just tried this, compiled with no error. You may need to set a compile option to allow extended syntax or open parameters...(I'm using D7)

procedure tMyClass.Add(aData: trec);
begin
  move(aData,fRec^,fRecLen);
end;
0
 
LVL 7

Expert Comment

by:LRHGuy
ID: 11963627
Or:

procedure Add(aData:trec);
begin
  trec(fRec^):=aData;
end;

works too...
0
 
LVL 17

Assisted Solution

by:Wim ten Brink
Wim ten Brink earned 250 total points
ID: 11963639
The Add method must either have an untyped variable or a pointer to a record. A pointer would be the best option here, I think. (Because untyped variables might be stored on the stack, thus disappearing from memory once the Add() method is done...

Also keep in mind that you cannot use TRecordName anywhere in your class because you don't want to know what type it is. You want more abstraction. I don't think you should declare TRecordName in unit1 anymore either. Your class will have to deal with pointers only that point to a record of a fixed size. Your class won't be able to handle the data in any way that's in the record. All it can do is read it from file or write it to file. This is called abstraction, making the class more usable to manage different types of data but also making the class less able to handle the data.

This:
  Procedure Add(ABC : TRecordName);
must be:
  Procedure Add(ABC : Pointer);
or:
  Procedure Add(var ABC);
or:
  Procedure Add(const ABC);

But abstraction of data works much better with classes than records.

You might consider using a TFileStream instead of a File, btw. If you keep writing just one type of record to it, it will just maintain a "file of type" layout... I feel that you're trying to build some stream-type here, reinventing a wheel that's already spinning quite well...
0
 

Author Comment

by:winuser2000
ID: 11963776
ok, i think i'll give up on this idea - i'd prefer to keep the functionality of the class as it works well so far with my records.

gonna up the points and split them between you both for the help

thanks.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

25 Experts available now in Live!

Get 1:1 Help Now