「C++プログラマであるかを見分ける10の質問」に答えてみた。
「C++プログラマであるかを見分ける10の質問」に答えてみた。自分の解釈だとこんな感じ。正解かどうか、特に2のreinterpret_castと10は自信なし。ちなみに、Java版は/.Jの日記で。
1. iterator の役割について説明せよ.
ポインタがメモリのアドレスを指し示すように、イテレータはコンテナの中身を指し示す。ポインタとの違いは、コンテナの「先頭」と「終端」を意味する値があること。
2. *_cast およびCスタイルのキャストそれぞれについて概要を説明せよ.
Cスタイルのキャスト:単なる型変換。数値ならば精度が落ちる場合がある。
static_cast:同上。C++での静的変換はCスタイルのキャストではなく、こっちを使用するべき。
reinterpret_cast:ポインタ同士、もしくは、ポインタと同サイズの整数型とのキャスト。メモリイメージの無理矢理コピー、精度落ちとかは無し。
dynamic_cast:継承関係が直系の子孫で無ければ、ポインタならばNULLとなり、参照ならばstd::bad_castが投げられる。*1
const_cast : constを外す。原則として使用不可。どうしても使用しなければならない場合のみ使うこと。代替手段は必ず存在する。
03/08:static_castとreinterpret_castについて勘違いがあった。orz http://d.hatena.ne.jp/A7M/20110308/1299558334
3. overload と override と hiding の違いについて説明せよ.
overload:メソッドの多重定義。同名でも引数の違いで区別する。
override:メソッドの上書き。サブクラスで同一名称、同一引数のクラスの挙動を変える。
hiding:名前隠蔽。サブクラスで継承元のメソッドやメンバ変数を参照できなくする。
4. const の機能について概要を説明せよ.
値が「不変」であることを保証する。てか、変えられない。
5. 多重継承について概要を説明せよ.
私は、プログラマであり、横浜FCサポーターであり、呑兵衛である。*2
assert(!dynamic_cast<FMarinosSuppoter*>(&A7M)); // 私は、マリノスサポではありません。
6. ポインタの使用方法について,メモリーリーク問題等と絡ませながら戦略を述べよ.
おもちゃ(メモリ)で遊んだ後は自分でおもちゃを片付ける。ポインタはお部屋(OS)に広げたおもちゃがどこにあるかを知らせてくれる。
おもちゃが出しっぱなしならば、お部屋がおもちゃでいっぱいになって、自分がそのおもちゃに躓いて怪我をすることも。
スマートポインタマジ便利。スマートポインタは後片付けを自動的にしてくれる。
7. コピーコンストラクタおよび代入演算子の扱いにおける戦略について述べよ.
コピーコンストラクタ:無から有を生み出す。
代入演算子:すでにあるものを後から上書きする。
8. virtual デストラクタの概要および使用上の戦略について述べよ.
virtualの場合、オブジェクトを生成したコンストラクタに対応するデストラクタが実行される。virtualでない場合は、変数型のデストラクタが実行される。
9. コンストラクタ,デストラクタにおける例外処理についての戦略を述べよ.
コンストラクタの場合:料理を作りたくても、材料や道具が揃わないことはよくあります。未完成な料理は出せないでしょ?
デストラクタの場合:料理の後片付けをしている最中にトラブる可能性は十分考えられます。後始末はきっちりと。
10. 抽象クラスとテンプレートクラスの使い分けについてインターフェースと言う観点から述べよ.
抽象クラスの「振る舞い」は継承元を含めたクラスに依存する。
テンプレートクラスの「振る舞い」は継承関係に依存しないが、「名前」に依存する。
Open Tools API その4:続・ソースエディタへのアクセス ソースエディタの「中身」をいじる
エディタの編集バッファ
ビュー(IOTAEditView)のBufferプロパティがソースエディタ内部のバッファで、ソースファイルの中身を編集する。インターフェースはITOAEditBuffer。
ソースエディタが1つのファイルをオープンしている場合、ビューは複数あっても、バッファは同一のを参照する。ソースエディタ(IOTASourceEditor)、ビュー(IOTAEditView)、バッファ(ITOAEditBuffer)の関係はこんな感じ。
┌ ビュー[0] ┐ ├ ビュー[1] ┤ ソースエディタ ┼ ビュー[2] ┼ バッファ │ … │ └ ビュー[n] ┘
バッファのEditBlockプロパティがエディタで選択されている範囲。以下は、エディタの選択部分の位置と内容を取得する例。
function GetCurrentSourceEditor: IOTASourceEditor; var i: Integer; Editor: IOTAEditor; ISourceEditor: IOTASourceEditor; CurrentModule: IOTAModule; begin Result := nil; CurrentModule := (BorlandIDEServices as IOTAModuleServices).CurrentModule; for i := 0 to CurrentModule.GetModuleFileCount - 1 do begin Editor := CurrentModule.GetModuleFileEditor(i); if Supports(Editor, IOTASourceEditor, ISourceEditor) then begin Result := ISourceEditor; Break; end; end; end procedure TfrmEditorStatus.Button2Click(Sender: TObject); var SourceEditor: IOTASourceEditor; EditBuffer: IOTAEditBuffer; Start, After: TOTACharPos; BlockType: TOTABlockType; begin SourceEditor := GetCurrentSourceEditor; // 現在アクティブなエディタを取得(GExpters由来) if SourceEditor = nil then Exit; Start := SourceEditor.BlockStart; // 選択範囲の開始位置 After := SourceEditor.BlockAfter; // 選択範囲の終了位置 // 現在編集中のファイルのバッファを取得 EditBuffer := (BorlandIDEServices as IOTAEditorServices).TopBuffer; if SourceEditor = nil then Exit; // 選択範囲の内容を取得 Memo1.Clear; Memo1.Text := EditBuffer.EditBlock.Text; end;
バッファへ直接アクセスする
セレクションではなく、バッファを直接アクセスする場合は、編集リーダー(IOTAEditReader)と編集ライター(IOTAEditWriter)を介してアクセスする。バッファはUTF-8で管理しているので、UnicodeStringからは明示的に変換してやらないと文字化けするので注意。
バッファの中身を読み取る手順は、エディタのCreateReaderメソッドで編集リーダーを生成し、GetTextメソッドで中身を取得する。
以下は、GExpertsのユーティリティ関数で、エディタのバッファからTStreamへ中身を読み込むもの。
// 編集リーダーからTStreamへ読み込む procedure GxSaveReaderToStream(EditReader: IOTAEditReader; Stream: TStream; TrailingNull: Boolean); const // Leave typed constant as is - needed for streaming code. TerminatingNullChar: AnsiChar = #0; var EditReaderPos: Integer; ReadDataSize: Integer; Buffer: array [0 .. EditReaderBufferSize] of AnsiChar; // Array of bytes, might be UTF-8 begin Assert(EditReader <> nil); Assert(Stream <> nil); EditReaderPos := 0; ReadDataSize := EditReader.GetText(EditReaderPos, Buffer, EditReaderBufferSize); Inc(EditReaderPos, ReadDataSize); while ReadDataSize = EditReaderBufferSize do begin Stream.Write(Buffer, ReadDataSize); ReadDataSize := EditReader.GetText(EditReaderPos, Buffer, EditReaderBufferSize); Inc(EditReaderPos, ReadDataSize); end; Stream.Write(Buffer, ReadDataSize); if TrailingNull then Stream.Write(TerminatingNullChar, SizeOf(TerminatingNullChar)); // The source parsers need this end; // ソースエディタの中身をTSTringsにロードする procedure GxLoadSourceEditorToUnicodeStrings(SourceEditor: IOTASourceEditor; Data: TStrings); var MemStream: TMemoryStream; begin Data.Clear; if not Assigned(SourceEditor) then raise Exception.Create ('No source editor in GxOtaLoadSourceEditorToUnicodeStrings'); // TODO: Check stream format for forms as text (Ansi with escaped unicode, or UTF-8) in Delphi 2007/2009 MemStream := TMemoryStream.Create; try GxSaveReaderToStream(SourceEditor.CreateReader, MemStream, False); MemStream.Position := 0; {$IFDEF UNICODE} Data.LoadFromStream(MemStream, TEncoding.UTF8); {$ELSE} if RunningDelphi8OrGreater then SynUnicode.LoadFromStream(Data, MemStream, seUTF8) else SynUnicode.LoadFromStream(Data, MemStream, seAnsi); {$ENDIF} finally FreeAndNil(MemStream); end; end;
どうも、CreateReaderで生成した編集リーダーは明示的に破棄する必要はなさそう。
一方、書き込む場合はIOTASourceEditorのCreateUndoableWriter*1メソッドで編集ライターを生成して、DeleteToメソッドで中身を削除したり、Insertメソッドで挿入する。
これまた、GExpertsのコードの一部。この関数は、エディタの中身を文字列で丸々入れ替える例。
procedure GxReplaceEditorText(SourceEditor: IOTASourceEditor; Text: string); var Writer: IOTAEditWriter; begin Assert(Assigned(SourceEditor)); Writer := SourceEditor.CreateUndoableWriter; if not Assigned(Writer) then raise Exception.Create('No edit writer'); Writer.DeleteTo(MaxLongint); Writer.Insert(PAnsiChar(AnsiToUtf8(Text))); Writer := nil; end;
文字列をAnsiToUtf8関数で明示的にUTF-8へ変換して、そのポインタを渡している。編集ライターも明示的に破棄する必要は無いみたい。
Open Tools API その3:ソースエディタへのアクセス
モジュール
モジュールとはIDEがアクセスする抽象的なエディタの組み合わせのことで、Delphi/C++Builderのプロジェクトにおけるユニットに相当。ユニットがソースファイル(*.pas/*.cpp)やヘッダファイル(*.h)、フォームファイル(*.dfm)の組み合わせであるように、モジュールは1つ以上のテキストエディタとフォームエディタなどから構成される。
モジュールに対するインターフェースを提供するのがIOTAModuleで、IDEからはIOTAModuleServiceより取得します。以下は、IDEが参照しているファイルの一覧を列挙する例。
procedure TfrmEditorStatus.Button6Click(Sender: TObject); var I, J: Integer; ModuleServices: IOTAModuleServices; Editor: IOTAEditor; SourceEditor: IOTASourceEditor; FormEditor: IOTAFormEditor; begin // モジュールの取得 ModuleServices := (BorlandIDEServices as IOTAModuleServices); with ModuleServices do begin // IDEが開いているモジュールの列挙 for I := 0 to ModuleCount - 1 do begin Memo1.Lines.Add(Modules[I].FileName); // モジュールが参照するエディタの列挙 for J := 0 to Modules[I].GetModuleFileCount - 1 do begin Editor := Modules[I].GetModuleFileEditor(J); if Supports(Editor, IOTASourceEditor, SourceEditor) then begin // エディタはソースエディタ Memo1.Lines.Add('SourceEditor - ' + SourceEditor.FileName); end else if Supports(Editor, IOTAFormEditor, FormEditor) then begin // エディタはフォームエディタ Memo1.Lines.Add('FormEditor - ' + FormEditor.FileName); end else begin // 不明 Memo1.Lines.Add('Unknown - ' + Editor.FileName); end; end; end; end; end;
エディタの種類の判別には、Supports関数でそれぞれのインターフェースをサポートするかどうかで判別する。
ソースエディタ、ビュー
ソースエディタのインターフェースがIOTASourceEditorで、ソースエディタは複数個のビュー(IOTAEditView)から構成される。EditViewCountプロパティがビューの個数で、この値が0の場合はサブビューが隠れていることを表しす。ビューそのものはEditViews[n]でアクセスする。
ビューがエディタそのもので、カーソル位置やセレクション情報、内部バッファなどの情報をもつ。
IOTAEditViewの主なプロパティ
プロパティ | 型名 | 内容 |
---|---|---|
Block | IOTAEditBlock | ブロック:エディタの選択範囲 |
Buffer | IOTABuffer | バッファ:エディタの内部バッファ |
Position | IOTAEditPosition | カーソル位置 |
TopRow | Integer | 最上部に表示されている行の行番号 |
RightColumn | Integer | ビューの右端の桁番号 |
第19回 エンバカデロ・デベロッパーキャンプでしゃべります。
毎度お馴染みですが、第19回 エンバカデロ・デベロッパーキャンプでまたしゃべります。
内容は、過去に掲載したOpen Tools APIに関する3点と、
- Open Tools API その0:概要 - C++Builder好きの秘密基地
- Open Tools API その1:"Hello,World!"を表示してみる - C++Builder好きの秘密基地
- Open Tools API その2:メニューの差し替えとノーティファイアインターフェース - C++Builder好きの秘密基地
現在執筆中のコードエディタへのアクセスの件*1をベースに、Twitter APIをラップするDelphiコンポーネントであるTTwitterを使って、Delphi/C++BuilderのIDEをTwitterクライアント化してしまうという、デブキャンプ史上最も誰得な無茶振りネタ。
TTwitterの動作は確認しているけど、最悪のケースとして、RubyかPython製のTwitterクライアントをIDEからコンソールアプリとして呼び出す可能性も無きにしも非ず。(ぉ
てか、とっとと、デモ用アプリとプレゼンを作れ!>俺
*1:何とか今度の連休中に完成させたい
C++Builder XE Starter/Delphi XE Starterが発表
かねてから要望が多かった個人向けエディションのC++Builder XE Starter/Delphi XE Starterが発表。
Delphi関連は有志の方がまとめてくれているのでC++Builderの分について少々。
個人的にC++Builder XE Starterの機能でカットされていて残念なのは、メモリリークやリソースリークとかを検知するCodeGuard。これ、バッファオーバーフローとかも検知してくれるから、C/C++初心者が嵌りやすいポインタ絡みの件を解決するのに便利なんだよね…。
MS HELP2もカットだから、これはdocwikiを直接参照する形式になるのかも。
あと、今度こそTurbo Explorerのように気がついたらフェードアウトではなく、少々のタイムラグがあってもPro/Ent/Arch版と同様にバージョンアップを続けて欲しい。
Delphi/C++Builderだけではなく、有償、無償の任意のIDEやソフトウェア開発ツールを持っているユーザーも該当 RT @ran_bousyo delphi xe starterのアップグレード価格は¥14,000(税別)URL
2011-02-01 16:22:17 via web to @ran_bousyo
Unified InterbaseをC++Builder XEで試してみた。
かねてから、Pro版で使用可能なFirebird/Interbase用のコンポーネントを探していて、
という記事がポストされていたので、Unified InterbaseをC++Builder XEで試してみた。
インストールは、C++Builder XEではC++Builder 2009用のプロジェクトファイル"UIBBCB12Win32.groupproj"を開いてC++Builder XE用に変換。あるいは、UIBD15Win32.groupprojを開いて、プロジェクトオプションの[C/C++ 出力ファイルの生成]を"すべての C++ Builder ファイル(パッケージ ライブラリを含む)を生成"にすればOK。
ただし、ビルド時にuiblib.pasから生成されるuiblib.hppで以下のエラーが発生してコンパイルエラーになる。
[BCC32 エラー] uiblib.hpp(284): E2019 'TUIBSQLVar:: :: :: ()' は無名の共用体内では宣言できない [BCC32 エラー] uiblib.hpp(298): E2019 'TUIBSQLVar:: :: ()' は無名の共用体内では宣言できない
このエラーを回避するには、パッケージのビルド時に生成される$(BDSCOMMONDIR)\hpp\uiblib.hppを編集して、TUIBSQLVar内部の無名構造体にダミーな適当な構造体名をつけてやればOK。
struct DECLSPEC_DRECORD TUIBSQLVar { public: short SqlType; short SqlScale; short SqlSubType; short SqlLen; char *SqlData; short *SqlInd; #pragma pack(push,1) union { struct __0 // ←ダミーの構造体名を追加 { TUIBParamsFlags Flags; unsigned:8; System::Word ID; short MaxSqlLen; short ParamNameLength; System::StaticArray<char, 125> ParamName; }; struct __1 // ←こっちもダミーを追加 { short SqlNameLength; System::StaticArray<char, 32> SqlName; short RelNameLength; System::StaticArray<char, 32> RelName; short OwnNameLength; System::StaticArray<char, 32> OwnName; short AliasNameLength; System::StaticArray<char, 32> AliasName; }; }; #pragma pack(pop) };
C++Builder用のサンプルコードである、examples\UIB\BCB6\Query\Query.bprをビルドして、Firebird 2.1のサンプルにある"EMPLOYEE.FDB"を読ませてみたところ無事動作。何となく使えそうだけど、TUIBDataSetが読み込み専用っぽいのが残念。この辺がうまくいけばDBコンポーネントと連携させられるんだけどね…。*1
JVCLのTJvBalloonHintを使う
QC#66768によると、TBallonHintは任意の位置にバルーンヒントを表示できないっぽい*1ので、代替としてJVCLのTJvBalloonHintを使ってみる。
TJvBalloonHintはTBallonHintをJVCLが拡張したコンポーネントでは無いので、使い方が根本的に違う。あと、現時点での最新版である3.40では、Windows 7でビジュアルスタイルが有効な場合でヒントが表示されないバグがあるので、$(JVCL)\run\JvBalloonHint.pasをSVNリポジトリの最新版と差し替える必要がある。
使い方は単純でツールパレットのJv Non-VisualにあるTJvBalloonHintをフォームに貼り、ActivateHintを呼び出すだけ。ヒントの表示はActivateHintの他にActivateHintPos、ActivateHintRectがあるので、用途によって使い分けられる。以下は、ActivateHintPosの例。
// ポップアップの表示位置を計算 TForm* pMainForm = Application->MainForm; TControl* pControl = pMainForm->ActiveControl; TRect R = pControl->ClientRect; TPoint P = TPoint(R.Left + R.Width() / 2, R.Bottom); P = pControl->ClientToScreen(P); P = pMainForm->ScreenToClient(P); // ヒント文字列の生成(HTMLタグの除去) UnicodeString Hint = HTMLPrepareText(pControl->Hint); Hint = AnsiReplaceText(Hint, L"<html>", UnicodeString()); Hint = AnsiReplaceText(Hint, L"</html>", UnicodeString()); // ヒントの表示 JvBalloonHint1->ActivateHintPos(pMainForm, P, Key, Hint);
11/05/26 追記:
ShowHintは問題なく動作。ShowHintの座標系はスクリーン座標系なので、ClientToSceenで変換してやること。*2