Upload
mohri-haruyuk
View
790
Download
10
Embed Size (px)
Citation preview
インターフェイスの基礎、 Firemonkey と VCL の違いなど毛利春幸
Firemonkey と VCL の違いなど• って書いてますが。。。• FireMonkey と VCL は全く違うのです。
復習• 釈迦に説法お許しくださいませ• 次のスライドがわからないければインターフェイスは書けないと思います
Delphi ポインター (1)
• ポインターvar i: Integer; pi: ^Integer;begin i := 100; pi := @i; Caption := Format('%d', [pi^]);end;
Delphi ポインター (2)
• ポインターvar rect: TRectF; prect: PRectF;begin rect := TRectF.Create(0,0,100,100); prect := @rect; Caption := Format('x1=%f, y1=%f, x2=%f, y2=%f', [prect^.Left, prect^.Top, prect^.Right, prect^.Bottom]);
end;
Delphi ポインター (3)
• ポインター渡し
• const ある時と無い時何が違いますか?
procedure TForm1.proc1(const prect: PRectF);begin Caption := Format('x1=%f, y1=%f, x2=%f, y2=%f', [prect^.Left, prect^.Top, prect^.Right, prect^.Bottom]);end;
procedure TForm1.Button1Click(Sender: TObject);var rect: TRectF;begin rect := TRectF.Create(0,0,100,100); proc1(@rect);end;
Delphi ポインター (4)
• const ポインタアドレス変更不可procedure TForm1.proc1(const prect: PRectF);var rect2: TRectF;begin prect^.Top := 1; rect2 := TRectF.Create(0,0,1,1); prect := @rect2; Memo1.Lines.Append( Format('x1=%f, y1=%f, x2=%f, y2=%f', [prect^.Left, prect^.Top, prect^.Right, prect^.Bottom]));end;
procedure TForm1.Button1Click(Sender: TObject);var rect: TRectF; prect_: PRectF;begin rect := TRectF.Create(0,0,100,100); prect_ := @rect; proc1(prect_); Memo1.Lines.Append( Format('x1=%f, y1=%f, x2=%f, y2=%f', [prect_^.Left, prect_^.Top, prect_^.Right, prect_^.Bottom]));end;
Delphi ポインター (5)
• var は?procedure TForm1.proc1(var prect: PRectF);var rect2: TRectF;begin prect^.Top := 1; rect2 := TRectF.Create(0,0,1,1); prect := @rect2; Memo1.Lines.Append( Format('x1=%f, y1=%f, x2=%f, y2=%f', [prect^.Left, prect^.Top, prect^.Right, prect^.Bottom]));end;
procedure TForm1.Button1Click(Sender: TObject);var rect: TRectF; prect_: PRectF;begin rect := TRectF.Create(0,0,100,100); prect_ := @rect; proc1(prect_); Memo1.Lines.Append( Format('x1=%f, y1=%f, x2=%f, y2=%f', [prect_^.Left, prect_^.Top, prect_^.Right, prect_^.Bottom]));End;
Delphi ポインター (class)
• class も同じです ( ポインターのコピーです )TTest = class Fi: Integer; end;
procedure TForm1.proc2(test: TTest);begin test.Fi := 2;end;
procedure TForm1.Button2Click(Sender: TObject);var t: TTest;begin t := TTest.Create; t.Fi := 1; proc2(t); Memo1.Lines.Append(Format(‘%d’, [t.Fi])); 答えは 2 ですend;
Delphi ポインター (record)
• record は実態のコピーです TTest = record Fi: Integer; end;
procedure TForm1.proc2(test: TTest);begin test.Fi := 2;end;
procedure TForm1.Button2Click(Sender: TObject);var t: TTest;begin t := TTest.Create; t.Fi := 1; proc2(t); Memo1.Lines.Append(Format(‘%d’, [t.Fi])); 答えは 1 ですend;
Delphi record constructor
• record constructor create は引数ある時だけ TTest = record Fi: Integer; constructor Create(i: Integer); end;
Delphi record property
• function, procedure, property TTest = record private function geti: Integer; procedure seti(const i: Integer); public Fi: Integer; constructor Create(i: Integer); property i: Integer read geti write seti; end;
var t: TTest;begin t := Ttest.Create(11); t.i := 12;
Delphi record 継承は無理• record は継承できない TTest = record private function geti: Integer; procedure seti(const i: Integer); public Fi: Integer; constructor Create(i: Integer); property i: Integer read geti write seti; end; TTest1 = record(Ttest) end;[dcc32 エラー ] Unit1.pas(20): E2029 'END' が必要な場所に '(' があります
TTest1 = class(Ttest) end;[dcc32 エラー ] Unit1.pas(20): E2021 クラス型が必要です
//C++ だと struct a1 {}; struct a2 : public a1{};
Delphi class
• class constructor Create; TMyClass = class→ 何も指定してないのに constructor Create; destructor Destroy; override; end;
constructor TMyClass.Create;begin inherited;→ これは TObject に行きますよねend;
Delphi class
• destructor Destroy; override; TMyClass = class→ 何も指定してないのに constructor Create; destructor Destroy; override; end;
destructor TMyClass.Destroy;Begin inherited; →同じく TObject に行きますend;
Delphi method
• procedure function TMyClass = class constructor Create; destructor Destroy; override; public procedure proc_1; function func_1: Boolean; end;
Delphi クラス継承• クラス継承 TMyClass = class
end; TMyClass1 = class(TMyClass) constructor Create; destructor Destroy; override; end;
Delphi クラス • virtual, override
• overload
TMyClass = class Fi: Integer; procedure pro1; virtual; end; TMyClass1 = class(TMyClass) constructor Create; destructor Destroy; override; procedure pro1;override; end;
TMyClass1 = class(TMyClass) constructor Create; destructor Destroy; override; procedure pro1;override; procedure pro2(i: Integer);overload; procedure pro2(i: String);overload; end;
Delphi クラス inherited
• inherited TMyClass = class Fi: Integer; procedure pro1; virtual; end; TMyClass1 = class(TMyClass) procedure pro1;override;end;
procedure TMyClass1.pro1;begin Fi := 2; inherited;end;
Delphi クラス virtual; abstract;
• virtual; abstract; TMyClass = class Fi: Integer; procedure pro1; virtual; abstract; end; TMyClass1 = class(TMyClass) constructor Create; destructor Destroy; override; procedure pro1;override; procedure pro2(i: Integer);overload; procedure pro2(i: String);overload; end;
procedure TMyClass1.pro1;begin Fi := 2; inherited; →この場合の inheri は無視されるend;
Delphi クラス private protected public published
• private protected public published TMyClass1 = class(TMyClass) private → 他所から見えない protected→ 継承は観れる public→ 見れる published→ コンポーネント化した場合オブジェクトインスペクタに出てくる end;
Delphi class method
• class method TMyClass1 = class(TMyClass) class procedure pro1;end;
class procedure TMyClass1.pro1;begin// Fi := 2; ローカル参照できない inherited;→ インヘリは使えるみたいですend;
TFoo = record class function Foo1: Integer; static; → static にすれば OK inline; static; でも OK end;
Delphi method inline
• method inline• ルーチンに inline 指令を指定できるこれは、コンパイラに対して、そのルーチンを実際に呼び出す代わりに、呼び出し側にそのルーチンを含むコードを出力するよう指示します。
Delphi クラスヘルパー• クラスヘルパー TMyClass1 = class(TMyClass) constructor Create; destructor Destroy; override; class procedure pro1; protected procedure pro2(i: Integer);overload; procedure pro2(i: String);overload; end;
TMyClass1Helper = class helper for TMyClass1 procedure pro3; end;
procedure TMyClass1Helper.pro3;begin pro2(1);end;
var t: TMyClass1;begin t := TMyClass1.Create; t.pro3;end;
Delphi クラスのネスト• クラスのネスト TMyClass1 = class(TMyClass) constructor Create; destructor Destroy; override; class procedure pro1; private type TBar = class class function func1: Integer; end; procedure pro2(i: Integer);overload; procedure pro2(i: String);overload; end;
Delphi operator
• operator TOpTest = record Fi: Integer; class operator Add(a, b: TOpTest):TOpTest; end;
class operator TOpTest.Add(a, b: TOpTest): TOpTest;begin a.Fi := a.Fi + b.Fi; Result := a;end;
procedure TForm1.Button2Click(Sender: TObject);vara, b: TOpTest;Begin a := a + b;end;
struct TTest {int Fi = 0;TTest operator+(TTest i1){
i1.Fi = Fi + i1.Fi;return i1;
}};
TTest a;TTest b;a = a + b;
Delphi operator(2)
• operator
その他いろいろあります
Delphi TNotifyEvent, TGetStrProc
• よく使いますねtype TMyClass = class FOnEv: TNotifyEvent; property OnEvent: TNotifyEvent read FOnEv write FOnEv; end;
var obj: TMyClass;begin obj:= TMyClass.Create; obj.OnEvent := Self.Button1Click;end;
BCB TNotifyEvent, TGetStrProc
• よく使いますねstruct TMyClass : public TObject{
TNotifyEvent FOnEv;void __fastcall test() {
if (!(FOnEv == NULL)) {FOnEv(NULL);
}}__property TNotifyEvent OnEv = {read = FOnEv, write = FOnEv};
};__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner){
TMyClass* myObj = new TMyClass();myObj->OnEv = this->DoEv;myObj->test();delete myObj;
}
void __fastcall TForm1::DoEv(System::TObject* Sender){
Caption = L" イベント発生 ";}
Delphi TProc<T>, TFunc<TResult>
• TProc<T>, TFunc<TResult> procedure TForm1.proc3(plocA: TProc<Integer>);var i: Integer;begin plocA(i);end;
procedure TForm1.proc3(funcA: TFunc<Integer,Single>);var i: Integer; r: SIngle;begin i := 100; r := funcA(i);end;
begin proc3(procedure (i: Integer) begin end); proc3(function (i: Integer): Single begin end);end;
BCB TProc<T>, TFunc<TResult>
• デルファイと同じですが、• class RTL_DELPHIRETURN DelphiInterface{}なんです。• typedef System::DelphiInterface<TProc>
_di_TProc; があります。
BCB TProc<T>, TFunc<TResult>
• BCB でラムダ渡す場合struct TMyClass : public TObject{
void __fastcall proc1(const System::Sysutils::_di_TProc proc_){
proc_->Invoke();}
};__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner){
TMyClass* myObj = new TMyClass();myObj->proc1([](){
for (int i =0; i < 10; i++) {Sleep(100);
}});delete myObj;
}
BCB TProc<T>, TFunc<TResult>
• 旧 BCB で渡す場合 TCppInterfacedObjectclass TSleepFunc : public TCppInterfacedObject<TProc>{public: TSleepFunc(TForm* Form) : FForm(Form) {} virtual void __fastcall Invoke(void) { Sleep(10000); // 時間のかかる処理 //Synchronize メソッドを使う TThread::Synchronize(TThread::CurrentThread, UpdateCaption); } void __fastcall UpdateCaption(void) { FForm->Caption = "OK"; }private: TForm* FForm;};void __fastcall TForm1::Button2Click(TObject *Sender){ Caption = "Start"; TThread::CreateAnonymousThread(new TSleepFunc(this))->Start();}
//////http://www.gesource.jp/weblog/?p=5097
BCB TProc<T>, TFunc<TResult>
• 旧 BCB で渡す場合 TCppInterfacedObjectstruct aaa : public TCppInterfacedObject<TProc>{
virtual void __fastcall Invoke(void){Sleep(1000);
};};
void __fastcall TForm1::FormCreate(TObject *Sender){
TThread::CreateAnonymousThread(new aaa())->Start();}
Delphi System.Generics.Collections
• 何かと話題の
おさらい まとめ• 問題なく 理解できてればインターフェイスも大丈夫です
インターフェイス• IInterface が元です。• IUnknown, や IInvokable も IInterface ですtype IInterface = interface ['{00000000-0000-0000-C000-000000000046}'] function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; {$IFNDEF SYSTEM_HPP_DEFINES_OBJECTS} {$NODEFINE IInterface} { defined in sysmac.h } {$ENDIF}
IUnknown = IInterface; {$EXTERNALSYM IUnknown} { from unknwn.h or sysmac.h }{$M+} IInvokable = interface(IInterface) end;{$M-} {$NODEFINE IInvokable} { defined in sysmac.h }
インターフェイス実装• これコンパル通ります。
• 使ってみます
ITest1 = interface(IInterface) ['{046D8512-6809-42F1-859E-3662231092CB}'] procedure proc1(); end; TTest1 = class(TInterfacedObject, ITest1) procedure proc1(); virtual; abstract; end;
var obj: ITest1;begin obj := TTest1.Create; obj.proc1;end;
インターフェイス実装• これコンパル通ります。
• 使ってみます
ITest1 = interface(IInterface) ['{046D8512-6809-42F1-859E-3662231092CB}'] procedure proc1(); end; ITest2 = interface(IInterface) ['{45E412F1-4275-44D6-9A04-A4065363B70A}'] procedure proc2(); end; TTest1 = class(TInterfacedObject, ITest1, ITest2) procedure proc1(); virtual; abstract; procedure proc2(); virtual; abstract; end;
インターフェイス実装 2
• Delphi インターフェイスは理解しやすい。var obj: ITest1;begin obj := TTest1.Create; obj.proc1; obj.proc2; エラーend;
var obj: ITest1; obj2: ITest2;begin obj := TTest1.Create; obj.proc1;
obj2 := (obj as TTest1); obj2.proc2;end;
BCB インターフェイス実装• __interface__interface ITest: public IInterface{public:
virtual void __fastcall proc() = NULL;
};
struct TTest : public TCppInterfacedObject<ITest>{
int FiTest;virtual void __fastcall proc(){
FiTest = 11;};
};using _di_ITest = System::DelphiInterface<Itest>;
__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
{_di_ITest obj = static_cast<ITest* >(new TTest());obj->proc();
}
TInterfacedObject, TAggregatedObject
• 使い分け• TAggregatedObject は後述する TInterfacedObject の Reference
Counter を共有するクラスです ( 細川さんのブログ )
BCB TList::Sort()• Sort(TListSortCompare Compare);• typedef int __fastcall (*TListSortCompare)(void * Item1, void * Item2);• なのでただの関数ポインタです。int __fastcall MySort(void *Item1, void *Item2){ return 0;}
std::tr1::shared_ptr<TList> slTemp(new TList());slTemp->Sort(MySort);
FMX と _di_TProc• FMX で this->Sort() なんてすると• _di_TFmxObjectSortCompare だったりします• TThread::CreateAnonymousThread() とか• System::Sysutils::_di_TProc ThreadProc だったり• インターフェイス渡しです。