前言 本文展示了歐洲計算機開發商協會正在發展的C++/CLI(一種不同的C++語言
它方便開發人員在微軟的
NET框架下更容易地開發程序)語言在C++語言上的擴展
寫這篇文章的目的並不是要建議標准C++包括這部分擴展
也不是對C++/CLI的認可
而只是在探討C++/CLI語言在這一領域的發展方向
一基礎知識 C++/CLI中的屬性是類似與各種數據成員(有各種操作限制)的可操作實體
但是這種操作往往被轉化為調用存取函數(這主要是
getter
和
setter
函數)
例如
struct Demo
{
property int Val { // 一個非常簡單的整型
分級屬性
int get() const {
++Demo
::access_count;
return this
>value;
}
void set(int v) {
++Demo
::access_count;
this
>value = v;
}
}
private:
int value;
static unsigned long access_count;
};
int main() {
Demo
d;
d
Val =
; // 調用
set
操作函數
return d
Val; //調用
get
函數
}
存取函數的名字必須是get 或者是 set函數
兩者之中的任何一個都可以被省略
但絕不能兩者全省略
省略一個存取函數導致只存在一個讀屬性或只存在一個寫屬性
屬性的地址是無法獲取的
然而
存取函數作 為成員函數理所當然地可以被用來產生指向成員的指針常量(例如
&Demo
::Val::set)
屬性可以使用關鍵字
virtual
進行聲明
這意味者存取操作函數是虛函數
純虛屬性函數也是可能存在的
例如
struct VirtualProp {
virtual property int Val =
{
int get() const; // 純虛函數
virtual void set(int v); //純虛函數
這裡關鍵詞
virtual
是多余的
}
//
};
上述例子顯示了通常情況下遇到的一些簡單的
非靜態的
分層次的屬性實例
C++/CLI文檔包含了大量的概念變化
下文將進行解釋
二動機 在標准C++的上下文中
屬性約定成俗地使用
get和set函數
文法
這種文法將暴露的數據和諧地轉換為封閉地狀態信息
在更精細的實時框架上下文中(具體的說是微軟的
NET框架)
屬性是可以通過映射實時發覺和修改的元素
例如
現代的GUI庫將它的組件參數聲明為屬性
可視化的界面構築工具裝載這些庫
使用裝載各種組件的屬性列表並將結果展現到用戶面前
當用戶修改了一個屬性
存取操作函數將被調用
例如這將觸發各種GUI更新事件
三屬性變量 除了上述代碼中聲明的簡單的分層屬性
C++/CLI還引進了其他幾種類型屬性變量
(一)靜態分層屬性
靜態分層屬性使用關鍵字
Static
來聲明
它們的存取操作函數是靜態的
靜態屬性的存取操作與靜態數據成員的存取操作非常一致
(例如
使用C::P語法來獲取C類的靜態屬性P)
(二)不明顯的分層屬性
一個屬性的定義(即括號內的存取操作函數聲明)可以使用分號
來代替
在這種情況下
get和set存取函數綜合成一個簡單的可以存取操作的屬性值
例如
C++/CLI定義的一個類如下
struct TrivialProp {
property int Val;
};
上述代碼從本質上與下述代碼相同
struct TrivialProp {
property int Val {
int get() const { return this
>__Val; }
void set(int v) { this
>__Val = v; }
}
private:
int __Val;
};
(三)指定索引屬性
使用操作數組成員的老語法
指定索引可以操作一個數值集合
下面的例子顯示了一維索引屬性的操作
struct Demo
{
property int x[std::string] {
int get(std::string s) const {
}
void set(int v
std::string s) {
}
}
//
};
int main() {
Demo
d;
std::string s(
CLI
);
d
x[s] =
; // Calls Demo
::x::set(
s)
return d
x[s]; // Calls Demo
::x::get(s)
}
注意
指定索引的屬性不能是靜態變量
多維的索引屬性也是可以的
它引入的操作語法與C/C++中數組元素操作方法不太一樣
例如
struct Demo
{
property double x[std::string
int] {
double get(std::string s
int n) const {
}
void set(double v
std::string s
int n) {
}
}
//
};
int main() {
Demo
d;
std::string s(
CLI
);
d
x[s
] =
; // Calls Demo
::x::set(
s
)
return d
x[s
] !=
; // Calls Demo
::x::get(s
)
}
後面的這一個例子說明了出現在括號內的操作索引屬性的逗號符號是表達式操作符號
而不是一個逗號操作符
(下面將討論這種規則帶來的後果)
(四)默認的索引屬性
除了對象被編入偽域外
默認的索引屬性與指定的索引屬性非常相象
對象本身可以索引(仿佛它自身有一個[]操作成員函數一樣)
以前的代碼只要稍微改動一下就可以說明這種變化
struct Demo
{
property double default[std::string
int] {
double get(std::string s
int n) const {
}
void set(double v
std::string s
int n) {
}
}
//
};
int main() {
Demo
d;
std::string s(
CLI
);
d[s
] =
; // Calls Demo
::default::set(
s
)
return d[s
] !=
; // Calls Demo
::default::get(s
)
}
請關注關鍵詞
default
代替屬性名的用法
四一些技術性問題 歐洲計算機制造商協會(C++/CLI標准的制訂者)已經研究並解決了引入屬性所帶來的若干問題
下面這些內容尤其值得關注
(一)多維索引屬性的操作
p
>x[
]表達式擁有不同的意思
這要視成員x是否是屬性(這種情況下逗號分隔兩個索引屬性)或其它成員變量(這種情況下逗號是個操作符號
表達式的意思等同於p
>x[
])而定
為了在一個屬性索引中獲取逗號操作符的效果
開發人員可以使用圓括號(即p
>x[(
)])
(注意
在依賴模版的表達式中
這將產生模糊性
並且直到實例化時問題才能得到解決)
(二)屬性名與類型名沖突
微軟
NET框架帶有很多包含屬性的類(這些類最初並不是使用C++/CLI來開發的)
這些包含的屬性名與屬性類型的名字相同
例如
typedef int Color;
struct Conflict {
property Color Color { // Property name hides type name
typename Color get() const;
void set(typename Color);
}
//
};
}
為了幫助在這種上下文中書寫代碼
C++/CLI計劃添加語法
使用關鍵詞typename來標識不標准的類型(特別是
屬性
)
查找標志符的過程中將被忽視
上述的代碼就以這種新的形式使用typename關鍵詞
(三)重載的索引屬性
索引屬性可以被重載
即
幾個指定索引屬性可以使用同一個名字共存於同一個類中
假定它們可以根據屬性的類型來區分開來
相似地
默認的索引屬性可以使用其他屬性或操作符[]來重載
解決兩意性與重載行為的規則已經被建立起來
來處理上述情況
(四)保留的成員名字
C++/CLI屬性通過綜合特定的成員來實現
這些成員的名義由微軟的
NET框架來規定
並且必須得到保留
如果一個類包含分層的屬性或指定索引屬性X
成員名 get_X 和set_X在類中得到保留(即使屬性僅僅包含一個操作函數也是這樣)
相似地
如果一個類包含有一個默認的索引屬性
類中的成員函數get_Item 和set_Item也將得到保留
From:http://tw.wingwit.com/Article/program/net/201311/12507.html