كيف يتم نسخ كلاس إلى آخر ؟
#1
السلام عليكم ورحمة الله وبركاتة
لتو بدأت مع الـ OOP بشكل جاد Smile , وها أنا في اول المطبات

سؤالي هو كتالي : كيف اقوم بنسخ محتويات كلاس إلى كلاس آخر ؟

لدي هذا الكود :
PHP كود :
unit Unit1;

interface

uses
  Windows
, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  
Dialogs, StdCtrls;

type
  TForm1 
= class(TForm)
    
btn1: TButton;
    
procedure btn1Click(Sender: TObject);
  private
    { Private 
declarations }
  public
    { Public 
declarations }
  
end;

  
TMyClass = class
  private
    
FAge: Integer;
    
FName: string;
    
FPhoneNumbers: TStringList;
    
procedure setPhoneNumbers(const Value: TStringList);
  public
    
property Name : string read FName write FName;
    
property Age : Integer read FAge write FAge;
    
property PhoneNumbers: TStringList read FPhoneNumbers
      write setPhoneNumbers
;
  
end;

var
  
Form1: TForm1;
  
Man1, Man2 : TMyClass;

implementation

{$R *.dfm}

{ 
TMyClass }

procedure TMyClass.setPhoneNumbers(const Value: TStringList);
var
  
i : Integer;
begin
  
for i := 0 to Value.count-1 do
  
begin
    FPhoneNumbers
.Add(Value.Strings[i]);
  
end;
end;

procedure TForm1.btn1Click(Sender: TObject);
begin
  
// create Man1 and fill its infos
  
Man1 := TMyClass.Create;
  
Man1.Name := 'Kahld';
  
Man1.Age := 15;
  
Man1.PhoneNumbers.Add('XXXXXXXXXXXX');
  
Man1.PhoneNumbers.Add('AAAAAAAAAAAA');
  
Man1.PhoneNumbers.Add('WWWWWWWWWWWW');

  
// Create Man2 and copy information form Man1
  //to Man2 ; How Can I do that ?
  
Man2 := TMyClass.Create;
  
// if I use this code
  
Man2 := Man1; // I give Man2 a pointer for Man1
  //so .. If i Free Man1.. Man2 will fo as well
end;

end. 

كيف أقوم بنسخ محتويات Man1 إلى Man2 ؟
اريــ ـد نسخ المحتويات وليس إعطاء Man2 مؤشر إلى محتويات Man1
حيث لو قمت بإستدعاء الدالة Free لـ Man1 , ستذهب المعلومات من Man2 كذلك !

وكذلك نفطة آخرى .. عندما استعمل الأمر :
PHP كود :
Man1.PhoneNumbers.Add('XXXXXXXXXXXX'); 
يحصل خطا حيث اني لم أعمل Create للقائمة .. هل يجب ان اعدل الدالة Create الخاصة بالكلاس واضع فيها امر انشاء القائمة ؟

اتمنى اني وضحت المشكلة
وشكراً لحسن القارءة
الرد
#2
السلام عليكم ..

فكرة رائعة و صائبة أن تتعلم ال oop .. صدقني عندما تتقنها ستندم لأنك لم تتعلمها في وقت سابق :eek:

إقتباس :سؤالي هو كتالي : كيف اقوم بنسخ محتويات كلاس إلى كلاس آخر ؟

للأسف , دلفي لا تدعم بشكل مباشر نسخ كلاس الى كلاس آخر .
لكن يمكن تطبيقها بطريقتين :
- الطريقة الأولى استعمال ال RTTI :
تعتمد هذه الطريقة على enum لجميع ال properties ثم اسناد قيمها الى الكلاس .
أسلوب عملها مشابه تماما لل Object Inspector .
بما أنك تتعلم خطوة بخطوة .. فأنا لا أنصحك باستعمالها حتى تتقن ال OOP بشكل جيد .

-الطريقة الثانية توريث الكلاس من TPersistent :

الكلاس TPersistent يحتوي على اجراء assign لنسخ الكلاس ..
لعلك لاحظت أن أغلب الكلاسات مورثة منه : TCanvas,TFont,TButton,..
الفكرة تعتمد على عمل override للاجراء AssignTo ثم اسناد القيم الى الكلاس الجديد .
ملاحظة : الطريقة الثانية هي الطريقة الشائعة في نسخ الكلاسات Big Grin

-------------------------------------------------------------------
دائما اجعل أول حرف من الدالة uppercase ..
PHP كود :
setPhoneNumbers
=> SetPhoneNumbers 
لمبرمجي دلفي فلسفة مع طريقة كتابة المتغيرات و الدوال في الكلاسات :
المتغيرات دائما تبدأ بحرف F اختصار الى Field .
و الدوال تبدأ بحرف uppercase .
يستحسن أن تستلزم بهذه المسلمات حتى يستطيع غيرك قراءة أكوادك Big Grin

إقتباس :يحصل خطا حيث اني لم أعمل Create للقائمة .. هل يجب ان اعدل الدالة Create الخاصة بالكلاس واضع فيها امر انشاء القائمة ؟

بالضبط , FPhoneNumbers عبارة عن Object .. و أي Object يجب أن يتم انشائه قبل استخدامه .

PHP كود :
type
  TMyClass 
= class(TPersistent)
  private
    
FAge: Integer;
    
FName: string;
    
FPhoneNumbers: TStringList;
    
procedure SetPhoneNumbers(const Value: TStringList);
  protected
    
procedure AssignTo(Dest: TPersistent); override;
  public
    
constructor Create; virtual;
    
destructor Destroy; override;
    
property Name: string read FName write FName;
    
property Age: Integer read FAge write FAge;
    
property PhoneNumbers: TStringList read FPhoneNumbers write SetPhoneNumbers;
  
end;

  { 
TMyClass }

procedure TMyClass.AssignTo(Dest: TPersistent);
var
  
LDst: TMyClass;
begin
  
if not(Dest is TMyClass) then
    raise Exception
.Create('Dest is not TMyClass !');
  
LDst := TMyClass(Dest);
  
LDst.FName := FName;
  
LDst.FAge := FAge;
  
LDst.FPhoneNumbers.Assign(FPhoneNumbers);
end;

constructor TMyClass.Create;
begin
  FPhoneNumbers 
:= TStringList.Create;
end;

destructor TMyClass.Destroy;
begin
  FreeAndNil
(FPhoneNumbers);
  
inherited;
end;

procedure TMyClass.SetPhoneNumbers(const Value: TStringList);
begin
  
if Value <> FPhoneNumbers then
    FPhoneNumbers
.Assign(Value);
end;

procedure TForm2.Button1Click(Sender: TObject);
var
  
Man1, Man2: TMyClass;
begin
  Man1 
:= TMyClass.Create;
  
Man1.Name := 'Kahld';
  
Man1.Age := 15;
  
Man1.PhoneNumbers.Add('XXXXXXXXXXXX');
  
Man1.PhoneNumbers.Add('AAAAAAAAAAAA');
  
Man1.PhoneNumbers.Add('WWWWWWWWWWWW');
  
Man2 := TMyClass.Create;
  
Man2.Assign(Man1);
  
Edit1.Text := Man2.Name;
  
Edit2.Text := IntToStr(Man2.FAge);
  
Edit3.Text := Man2.PhoneNumbers[0]
end; 

بالتوفيــــق .
Open Your Source .. Open Your Mind
الرد
#3
إقتباس :فكرة رائعة و صائبة أن تتعلم ال oop .. صدقني عندما تتقنها ستندم لأنك لم تتعلمها في وقت سابق
لا زلت اتذكر نصيحتك لي في احد المواضيع عندما قلت ان الـ OOP مهمه جداً..إلخ رغم اني لم اتبعها للاسف
لكن ما اجبرني على تعلم الـ OOP عندما بدأت البرمجة على C Plus Puls تحديداً على Qt Creator فهناك كان كل شيء
يتم من خلال OOP وبدون استعمالها لا استطيع برمجة برنامج جيد فاُجبرت على تعلم الـ OOP .. فانا من البداية كنت اتجنب
الإصطدم بـ OOP لني لم افهمها من المره الاولى xD

-----------------------------------
تمام كل شيء في مكانه Smile

لكن لدي سؤال صغير ماذا يقصد بالـ الكلمات التي تأتي بعد الدوال مثل
PHP كود :
virtual ,override ..etc 

وكذلك لماذا وضعت الدالة
PHP كود :
procedure AssignTo(Dest: TPersistent); override; 
في التغليف protected ؟ هل كي يتم توريثها عندما يتم وراثه هذا الكلاس من كلاس آخر او ماذا ؟
الرد
#4
إقتباس :لكن لدي سؤال صغير ماذا يقصد بالـ الكلمات التي تأتي بعد الدوال مثل
PHP كود :
virtual ,override ..etc 

virtual : تعني أن الدالة مسموح بأن يتم توريثها من الكلاس الابن
override : و تعني اعادة التوريث .
dynamic : تعمل نفس عمل virtual لكن الآلية مختلفة .
يفضل أن تستخدم virtual بدل dynamic لأن الأولى أسرع ..
سابقا عندما كانت الرام لا تتجاوز 32 مب كانوا يستخدمون dynamic لانها لا تستهلك من الرام الكثير ..لكنها بطيئة جدا مقارنة مع virtual .

الق نظرة على هذا المثال البسيط ليوضح لك الفكرة :

PHP كود :
program Project1;

{
$APPTYPE CONSOLE}
{
$R *.res}

uses
  System
.SysUtils;

type
  TBase 
= class(TObject)
    
procedure SayHi; virtual;
    
procedure SayGoodbye; virtual;

  
end;

  
TChildBase = class(TBase)
    
procedure SayHi; override;
    
procedure SayGoodbye;
  
end;

  { 
TBase }

procedure TBase.SayGoodbye;
begin
   Writeln
('The Base say goodbye :)');
end;

procedure TBase.SayHi;
begin
  Writeln
('The Base say hi :)');
  
SayGoodbye;
end;

{ 
TChildBase }

procedure TChildBase.SayGoodbye;
begin
  Writeln
('The Child say goodbye');
end;

procedure TChildBase.SayHi;
begin
  inherited
;
  
Writeln('The Child also say hi :)');
end;

var 
obj:TChildBase;
begin
   obj
:=TChildBase.Create;
   
obj.SayHi;
   
Readln;
end. 


إقتباس :وكذلك لماذا وضعت الدالة
PHP كود :
procedure AssignTo(Dest: TPersistent); override; 
في التغليف protected ؟ هل كي يتم توريثها عندما يتم وراثه هذا الكلاس من كلاس آخر او ماذا ؟

protected : تعني أن الدالة قابلة للنداء فقط من الكلاسات المورثة من الكلاس المصرحة بها
private : الدالة قابلة للنداء داخل ال Unit فقط .

في المثال الذي كتبته :
AssignTo : غير قابلة للنداء خارج الكلاس ..
بمعنى كود مثل هذا خاطئ :
PHP كود :
var 
   
m,x:TMyClass;
begin
   
...
   
m.AssignTo(x); //error!
   
...
end; 
ألق نظرة على هذا المثال :
PHP كود :
unit Unit2;

interface

type
  TBase 
= class(TObject)
    
procedure SayHi; virtual;
    
procedure SayGoodbye; virtual;
  protected
    
procedure LeaveMeAlone;
  private
    
procedure DoSomething;

  
end;

  
TChildBase = class(TBase)
    
procedure SayHi; override;
    
procedure SayGoodbye;
  
end;

implementation

{ TBase }

procedure TBase.DoSomething;
begin
  Writeln
('i am doing something ..');
end;

procedure TBase.LeaveMeAlone;
begin
  Writeln
('??????');
end;

procedure TBase.SayGoodbye;
begin
  Writeln
('The Base say goodbye :)');
end;

procedure TBase.SayHi;
begin
  Writeln
('The Base say hi :)');
  
SayGoodbye;
end;

{ 
TChildBase }

procedure TChildBase.SayGoodbye;
begin
  Writeln
('The Child say goodbye');
end;

procedure TChildBase.SayHi;
begin
  inherited
;
  
Writeln('The Child also say hi :)');
end;

end. 

PHP كود :
program Project1;

{
$APPTYPE CONSOLE}
{
$R *.res}

uses
  System
.SysUtils,
  
Unit2 in 'Unit2.pas';

type
  TMyClass 
= class(TChildBase)
    
procedure DoSomeWork;
  
end;

var
  
obj: TChildBase;

  { 
TMyClass }

procedure TMyClass.DoSomeWork;
begin
  LeaveMeAlone
;
  
DoSomething; // error !
end;

begin
  obj 
:= TChildBase.Create;
  
obj.SayHi;

  
Readln;

end. 
Open Your Source .. Open Your Mind
الرد
#5
SMP3 كتب :

فكرة رائعة و صائبة أن تتعلم ال oop .. صدقني عندما تتقنها ستندم لأنك لم تتعلمها في وقت سابق :eek:



دلني على مرجع مناسب للمبتدئين لتعلم oop بإستخدام دلفي.
الرد
#6
بالنسبة لي فهذا هو الكتاب الذي تعلمت منه الـ OOP في دلفي
من تأليف "عروة علي عيسى"
http://www.delphi4arab.net/forum/showthread.php?tid=97
الرد
#7
أفضل و سيلة هي الاطلاع على كلاسات دلفي .
Open Your Source .. Open Your Mind
الرد
#8
إقتباس :أفضل و سيلة هي الاطلاع على كلاسات دلفي
+1
فلا يوجد كتاب يتكلم عن كل ما تحتويه دلفي 100% على حد علمي


بالمناسبة اخي smp3 هل لك ان تذكر الطريقة المتبعه بإستخدام rtti يبدو اني ساحتاجها قريباً
الرد
#9
ALmuhhnad كتب :+1
فلا يوجد كتاب يتكلم عن كل ما تحتويه دلفي 100% على حد علمي


بالمناسبة اخي smp3 هل لك ان تذكر الطريقة المتبعه بإستخدام rtti يبدو اني ساحتاجها قريباً

ستحتاج الى أن تكون على علم بالتقنيات التالية :
[COLOR="Red"]- Generics & Collections
- OOP
- RTTI
[/COLOR]
خذلك أولا قهوة ثقيلة .. Big Grin
ثم توكل على الله ..
ثم اطلع على هذا الرابط :

كود :
http://delphihaven.wordpress.com/2011/06/09/object-cloning-using-rtti/

بعد ان تتطلع على الرابط .. يمكنك البدأ في دراسة طريقة عمل Object Inspector
كود :
http://www.delphi4arab.net/forum/showthread.php?tid=11010
المكون مبني بالكامل بال RTTI & Generics و بالطبع تصميم بال OOP .
Open Your Source .. Open Your Mind
الرد
#10
السلام عليكم

عندما تقوم بانشاء اوبجكت من كلاس فان هدا الأبجكت يشغل مساحة من الداكرة ولنسخ الأوبجكت يكفي معرفة المساحة التي يشغلها انظر المثال كتبته بشكل سريع

PHP كود :
unit Unit1;

interface

uses
  Windows
, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  
Dialogs;

type
  TForm1 
= class(TForm)
    
procedure FormCreate(Sender: TObject);
  private
    { Private 
declarations }
  public
    { Public 
declarations }
  
end;
 
Tmycls = class
    private

    public
      
FName : string;
      
procedure clonCedsit(s: string);

 
end;
var
  
Form1: TForm1;

implementation

procedure TMycls
.clonCedsit(s: string);
begin
    FName 
:= s;
end;

{
$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var 
obj1, obj2 : Tmycls;
begin
     obj1 
:= Tmycls.Create();
     
obj2 := Tmycls.Create();
     
obj1.clonCedsit('jamalcoder');
     
ShowMessage(IntToStr(obj1.InstanceSize));
     
CopyMemory(Pointer(obj2), Pointer(obj1), obj1.InstanceSize);
     
Self.Caption:= obj2.FName;
     
obj1.Free;
     
obj2.Free;
end;

end. 
لا اله الا أنت سبحانك اني كنت من الضالمين
الرد


التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم