c++ 屬性(轉)
c++ 屬性
“__declspec”是Microsoft c++中專用的關鍵字,它配合著一些屬性可以對標準C++進行擴充。這些屬性有:
align、allocate、deprecated、dllexport、dllimport、 naked、noinline、noreturn、nothrow、novtable、selectany、thread、property和uuid。
template <class T1, class T2> class KeyValuePair
{
private:
//-- 參數
T1 *Key;
//------值
T2 *Value;
public
:
KeyValuePair()
{
Key=new T1;
Value=new T2;
}
~KeyValuePair()
{
delete Key;
delete Value;
}
public :
T1 GetKey()
{
return this->Key;
}
T1 SetKey(T1 inputKey)
{
this->Key=inputKey;
}
private :
int m_old;
public:
//---------屬性----get--------set--------返回數據---屬性名稱
_declspec(property(get=GetOld,put=SetOld))int Old;
int GetOld(void)
{
return m_old;
}
void SetOld(int value)
{
m_old=value;
}
};
{
KeyValuePair<int,int> c1;
c1.Old=123;
cout<<c1.Old;
}
給C++添加屬性機制
來源:http://blog.csdn.net/pankun/archive/2006/02/08/594274.aspx
以前用DELPHI和C#時,對DELPHI和C#語法中的屬性感到十分方便,在讀寫屬性時能自動調用屬性的get, set函數或代碼.但我最喜歡的C++中沒有屬性機制.不過C++提供了范型編程和操作符重載機制,足以讓一切變成可能.
假定要添加屬性的類是目標類,給C++添加屬性機制,我的想法是建立一個類,重載此類的 "=" 操作符,這樣給這個類賦值時,會調用此類的operator = 函數,在此函數中調用目標類的類成員函數即可.但要調用目標類的類成員函數,需要目標類類指針和類成員函數指針.類成員函數指針的類型可以通過模板傳入.廢話不多說,代碼如下:(VC7中編譯通過,GCC還未測試)
Property.h
/*
by 劍神一笑
屬性定義單元
*/
#ifndef PROPERTY_H
#define PROPERTY_H
//輔助類,用來定義類成員函數指針類型
template<typename T, typename U>
class PropertyType
{
public:
//指向類成員函數的指針類型
typedef void (U::*SetProc)(const T&);
typedef const T& (U::*GetProc)();
};
//屬性基類
template<typename U>
class PropertyBase
{
protected:
//擁有這個屬性的類的指針
U* obj_;
public:
void SetObj(U *obj)
{
this->obj_ = obj;
}
};
//只寫屬性過程定義
template<typename T, typename U, typename PropertyType<T, U>::SetProc Set>
class WriteProperty: public PropertyBase<U>
{
protected:
//定義屬性set的函數指針
typename PropertyType<T, U>::SetProc SetValue;
public:
WriteProperty()
{
this->SetValue = Set;
}
void operator= (const T &value) const
{
(obj_->*SetValue)(value);
}
};
//只讀屬性過程定義
template<typename T, typename U, typename PropertyType<T, U>::GetProc Get>
class ReadProperty: public PropertyBase<U>
{
private:
//避免讓只讀屬性可寫
void operator= (const T&) {}
void operator= (const ReadProperty<T, U, Get>&) {}
protected:
//定義屬性get的函數指針
typename PropertyType<T, U>::GetProc GetValue;
public:
ReadProperty()
{
this->GetValue = Get;
}
operator T() const
{
return (obj_->*GetValue)();
}
};
template<typename T, typename U, typename PropertyType<T, U>::GetProc Get>
std::ostream& operator << (std::ostream &out, const ReadProperty<T, U, Get>& rv)
{
out << rv.operator T();
return out;
}
//讀寫屬性過程定義
template<typename T, typename U, typename PropertyType<T, U>::SetProc Set, typename PropertyType<T, U>::GetProc Get>
class ReadWriteProperty: public PropertyBase<U>
{
private:
typename PropertyType<T, U>::SetProc SetValue;
typename PropertyType<T, U>::GetProc GetValue;
//禁用賦值和拷貝構造
const ReadWriteProperty<T, U, Set, Get>& operator= (const ReadWriteProperty<T, U, Set, Get>&) {}
ReadWriteProperty(ReadWriteProperty<T, U, Set, Get>&) {}
public:
ReadWriteProperty()
{
SetValue = Set;
GetValue = Get;
}
const ReadWriteProperty<T, U, Set, Get>& operator= (const T &value) const
{
(obj_->*SetValue)(value);
return *this;
}
operator T() const
{
return (obj_->*GetValue)();
}
};
template<typename T, typename U, typename PropertyType<T, U>::SetProc Set, typename PropertyType<T, U>::GetProc Get>
std::ostream& operator << (std::ostream &out, const ReadWriteProperty<T, U, Set, Get>& rv)
{
out << rv.operator T();
return out;
}
//簡化函性定義的宏
//定義讀寫屬性
#define PROPERTY_DECLARE_RW(property_name, type, class_type, set, get) \
ReadWriteProperty<type, class_type, class_type::set, class_type::get> property_name;
//定義只讀屬性
#define PROPERTY_DECLARE_R(property_name, type, class_type, get) \
ReadProperty<type, class_type, class_type::get> property_name;
//定義只寫屬性
#define PROPERTY_DECLARE_W(property_name, type, class_type, set) \
WriteProperty<type, class_type, class_type::set> property_name;
#define INIT_PROPERTY(property_name) property_name.SetObj(this);
#endif//PROPERTY_H
//-------------------------華麗的分隔線-----------------------------
測試代碼
#include <iostream>
#include <string>
#include "Property.h"
using std::cin;
using std::cout;
using std::string;
class Test
{
private:
int value_;
string name_;
public:
Test(int value)
{
INIT_PROPERTY(Value);
INIT_PROPERTY(Name);
INIT_PROPERTY(WValue);
this->value_ = value;
name_ = "TestClass";
}
void SetValue(const int& value)
{
cout << "Set Value: " << value << std::endl;
this->value_ = value;
}
const int& GetValue()
{
cout << "Get Value: " << value_ << std::endl;
return value_;
}
const string& GetName()
{
return name_;
}
void ShowValue()
{
cout << "Value: " << value_ << std::endl;
}
//聲明可讀寫屬性,參數為: 屬性名,屬性類型,當前類名,Set函數,Get函數
PROPERTY_DECLARE_RW(Value, int, Test, SetValue, GetValue);
PROPERTY_DECLARE_R(Name, string, Test, GetName);
PROPERTY_DECLARE_W(WValue, int , Test, SetValue);
};
int main()
{
Test t(100);
t.ShowValue();
t.WValue = 999; //只寫屬性可以寫入
//int i = t.WValue; //只讀屬性無法讀取
t.Value = 200; //讀寫屬性可以寫入
int i = t.Value; //讀寫屬性可以讀取
cout << "i: " << i << std::endl;
cout << t.Name << std::endl; //只讀屬性可以讀取
//t.Name = "hello"; //只寫屬性無法寫入
cin.get();
return 0;
}
運行結果:
Value: 100
Set Value: 999
Set Value: 200
Get Value: 200
i: 200
TestClass
這種方法是類型安全的,但會讓目標類占用更多內存,而且屬性調用的函數必須為public的,另外為了讓屬性類能正確的取得目標類類指針,我使用了一個INIT_PROPERTY宏,這樣比較麻煩,需要在構造函數中對每個屬性調用一下,希望有更好辦法的朋友告知.
一般來說對于標準C++而言是不存在成員屬性這個概念的,以前大家都是用GetXXX/SetXXX來訪問或取得數據,好象也沒有感覺到任何不便。但是當我們用過C#之類的語言之后,我們總覺得C++這個方式太老土了。于是我們想去實現“屬性”這個C++語言缺乏的要素。事實上網絡上有很多人已經做了這部分工作,實現的方法有很多種,一種是用模板,一種是根據特定語言來寫的,如VC(指的是Microsoft實現的C++)。但是它們要么很復雜,要么很難記住它的準確用法,嗯我總是喜歡簡單的東西,因為太復雜的東東會讓我的頭腦當機。廢話少說,來看看如何實現。
在實現之前,我必需先探討一下為什么需要“屬性”這個東東。比如說下面雇員這個類:
| class CEmployee { public: int Old; //年齡 }; CEmployee employee; employee.Old=22; int old =employee.Old; |
它有一個成員變量,我們可以直接對它們進行賦值或者讀取,但是往往會缺少一個很重要的東東,就是不能對所賦值進行校驗,這可是個大問題,比如我們給Old一個負值,比如-50,程序運行時不會有任何錯誤,但是的確這個成員變量的值在邏輯上是不正確的。于是我們會寫上GetOld、SetOld.現在OK了,這個小問題解決了,但新問題來了。我們的類使用者,他們需要重新把他們的代碼成寫如下的樣子,而不是上面的那樣。
| CEmployee employee; employee.SetOld(22); int old =employee.GetOld(); |
你的伙伴一定會在寫代碼時詛咒你寫了一個垃圾的類。所以你決定要改變這個現狀。很幸運,你是MS的忠實用戶,而且你對于MSDN看很仔細,所以你知道可以這樣來寫
|
class CEmployee int GetOld(void) |
Very Good,上面的類完美地完成一個屬性所要做的目標,不過還有一點小問題,象我這樣比較笨的經常需要查找MSDN才會知道_declspec(property(get= GetOld,put=SetOld))int Old;這句話的含義,而且我也經常忘記它的具體寫法,比如put我常把它寫成了set,這總是讓我想起了使用C#的美好時光,它是可以寫成這個樣子的
| public class CEmployee { private int m_old; public int Old { get { return m_old; } set { if(value >0 && value <60) { m_old = value; } else { m_old =20; } } } } |
所以我想到可以利用C/C++中強大的武器宏,我們來定義幾個宏
| #define PROP(T,X) __declspec(property(get= __get##X,put= __put##X))T X; #define GETPROP(T,X) __declspec(property(get= __get##X))T X; //只讀屬性 #define SETPROP(T,X) __declspec(property(put= __put##X))T X; //只寫屬必 #define GET(T,X) T __get##X(void) #define SET(T,X) void __put##X(T value) |
說明一下:T 代表屬性的類型如int,double,CString,而X代表屬性名稱。如果你需要一個只讀屬性可以使用GETPROP,只寫屬性則可以使用SETPORP,然后對應使用一個GET或SET,當然如果你用PROP,而只用了一個GET或SET,也沒有錯,只是在編譯時會告訴你沒有一個__getXXX或__putXXX的方法。然后我們就可以這樣來寫我們的類。
| class CEmployee { private: int m_old; public: PROP(int ,Old) GET(int,Old) { return m_old; } SET(int,Old) { if( (value >0) && (value <60)) //這里的value你可把它和C#一樣當做關鍵字 { m_old = value; } else { m_old =20; } } }; |
好了,我們要做的工作已經做完了。當然這種方法還是有很多問題,比如不能使用C#中常用的索引屬性,靜態屬性等等。但是畢竟我們是C++程序員么,呵呵!最后,這種方法只是在VC下有用。
浙公網安備 33010602011771號