日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

再說變體結構

 獨孤求財 2012-03-28

問題來源: http://www.cnblogs.com/del/archive/2009/03/01/1032376.html#1464477

假如有這樣三種結構, 分別來描述: 直線、圓與三角形:
type
  {描述直線的結構}
  TLine = packed record
    ID: Integer;    {編號}
    x1,y1: Integer; {第一點}
    x2,y2: Integer; {第二點}
  end;

  {描述圓的結構}
  TCircle = packed record
    ID: Integer;  {編號}
    x,y: Integer; {中心點}
    r: Integer;   {半徑}
  end;

  {描述三角形的結構}
  TTriangle = packed record
    ID: Integer;    {編號}
    xa,ya: Integer; {a點}
    xb,yb: Integer; {b點}
    xc,yc: Integer; {c點}
  end;

//無需 SizeOf, 我們可以輕松看出三個結構的大小分別是: 20、16、28 字節(jié)


上面三個結構的數(shù)據(jù)有類似之處, 在實用中常常需要用一個綜合的結構替代它們;
這就像 Delphi 中的 TWMKey、TWMMouse、TWMClose 等近 200 個結構都可以用 TMessage 代替一樣.

下面是一個非常不好, 但容易理解的描述:
  TMyShape = packed record
    ID: Integer;
    x1, y1, x2, y2: Integer;
    x, y, r: Integer;
    xa, ya, xb, yb, xc, yc: Integer;
  end;

//此結構大小是 56 字節(jié)
//之所以說它不好是因浪費太多, 譬如記錄一個圓, 只需要 ID、x、y、r 四個字段, 會浪費其它 10 個字段.
//但如果需要一個結構同時描述一條直線、一個圓、一個三角的話, 這個結構是合適的; 這里討論的并不是這種情況.


我們在某一時刻只需要它來表示一個形狀(或者是直線、或者是圓、或者是三角);
假如我們讓結構按照最大的需要分配空間, 譬如三角需要最多(除 ID 外, 是 6*4 個字節(jié)), 就分配 24 字節(jié); 這個空間用來記錄一個圓或者直線也是足夠的.

Delphi 允許我們使用這樣的語法來定義(這就是所謂的變體結構):
  TMyShape = packed record
    ID: Integer;
    case Integer of
      0: (x1, y1, x2, y2: Integer);
      1: (x, y, r: Integer);
      2: (xa, ya, xb, yb, xc, yc: Integer); {注意結構成員無論如何是不能重名的}
  end;

//可以這樣查看一下: ShowMessage(IntToStr(SizeOf(TMyShape))); 
//它剛好是 28 字節(jié), 和上面的 TTriangle 大小一樣.
//用這個結構可以非常方便地描述上面三種圖形; 盡管有時也會有浪費, 但相比在使用時帶來的方便, 那是可以接受的.


把上面這種描述用表格表示一下:

共 28 個字節(jié)
用于三角時 ID xa ya xb yb xc yc
用于直線時 ID x1 y1 x2 y2
用于圓時 ID x y r

對這樣的一個結構變量(譬如是 rec: TMyShape)來講, 不管你是不是需要, rec.ID、rec.x1 ... rec.yc 等所有結構成員都是存在的;
但有些數(shù)據(jù)是共享一塊內存, 譬如 x1、x、xa 共享 4 個字節(jié); x2、r、xb 共享 4 個字節(jié), 這可以測試一下:
type
  TMyShape = packed record
    ID: Integer;
    case Integer of
      0: (x1, y1, x2, y2: Integer);
      1: (x, y, r: Integer);
      2: (xa, ya, xb, yb, xc, yc: Integer);
  end;
var
  rec: TMyShape;
begin
  rec.r := 123;
  ShowMessageFmt('%d, %d', [rec.x2, rec.xb]); {123, 123}
end;


咱們的 "彬" 朋友不明白的是 case Integer of ...
這里的 case 并不是咱們經常用的 case 語句(譬如它沒有 end;), 只是 Delphi 的語法規(guī)定而已;
case Integer of 中的 Integer 也沒有再占用 4 字節(jié)的空間(但接下了的例子會占用), 也只是語法形式.

考慮另一個問題: 我們僅從一個結構變量的數(shù)據(jù)能看出它具體描述的圖形類型嗎?
應該說: 這不容易看出; 其實, 在實用中我們很少會有這種要求.

假如非要從結構數(shù)據(jù)中識別圖形類型也可以, Delphi 提供了語法支持, 但這又要多占幾個字節(jié):
  TMyShape = packed record
    ID: Integer;
    case flag: Integer of
      0: (x1, y1, x2, y2: Integer);
      1: (x, y, r: Integer);
      2: (xa, ya, xb, yb, xc, yc: Integer);
  end;

//此時的結構大小應該是 32 字節(jié).
//像這樣, flag 也是一個結構成員, 也可以讀寫; 我們可以給 flag 賦不同的值以區(qū)別圖形類型.
//但不管 flag 這個值是什么, 都不會影響前面的內存共享機制; flag 也不會因為其他賦值而自動改變.


根據(jù)不同的需要, 上面的 flag 也可以是其他類型(譬如枚舉);
我也經常見到 case Boolean of 的用法, 這只能用在兩種可選狀態(tài)的情形, 譬如:
  TMyShape = packed record
    ID: Integer;
    case Boolean of
      True:  (x1, y1, x2, y2: Integer);
      False: (x, y, r: Integer);
  end;


Delphi 還有一個相近的概念 absolute(從變量的層面上共享內存), 參見:

http://www.cnblogs.com/del/archive/2009/02/19/1394037.html

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多