C++/CLI中可以定義兩種類型的struct和class類型,一種為數(shù)值類(或數(shù)值結(jié)構(gòu)):value class(value struct);一種是引用類(或引用結(jié)構(gòu)):ref class(ref value)。與本地C++一樣,class與struct的區(qū)別在于前者的成員默認(rèn)為私有,后者默認(rèn)為公有。下面僅以類來介紹,內(nèi)容同樣適用于結(jié)構(gòu)。
value class與ref class組成的是雙關(guān)鍵字,也就是說,單獨(dú)的value、ref并不是關(guān)鍵字。數(shù)值類與引用類的區(qū)別,以及它們與本地C++類的區(qū)別主要包括以下幾個(gè)方面:
-
數(shù)值類的對象包含自己的數(shù)據(jù),引用類的對象只能用句柄來訪問。
-
在C++/CLI中,函數(shù)成員不能聲明為const類型,取而代之的是字面值類型,修飾詞關(guān)鍵字為 literal。
-
在非靜態(tài)函數(shù)成員中,this指針類型與本地C++不同:數(shù)值類的this指針為內(nèi)部指針類型(interior_ptr<T>),而引用類的this指針為句柄類型(T^)。
-
C++/CLI類的數(shù)據(jù)成員不能包含本地C++數(shù)組或本地C++類對象。
-
C++/CLI類無友元函數(shù)。
-
C++/CLI類的數(shù)據(jù)成員不能包含位類型的數(shù)據(jù)成員。(什么是位數(shù)據(jù)類型)
-
C++/CLI類的函數(shù)成員不能有默認(rèn)的形參。
此外,在C++/CLI中,不推薦類命名時(shí)使用前綴‘C’,其成員變量命名也不用前綴’m_’。
一、定義數(shù)值類
數(shù)值類主要用于表示具有有限個(gè)數(shù)據(jù)成員的簡單對象,其定義方法與本地C++類基本相同。首先看一個(gè)定義數(shù)值類,以及使用類的完整例子。
- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::開始==>> [Ex7_14.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ex7_14.cpp : main project file.
#include "stdafx.h"
using namespace System;
// class representing a height
value class Height
{
private:
// Records the height in feet and inches
int feet;
int inches;
public:
// Create a height from inches value
Height(int ins)
{
feet = ins/12;
inches = ins%12;
}
// Create a height fromm feet and inches
Height(int ft, int ins) : feet(ft), inches(ins) {}
};
int main(array<System::String ^> ^args)
{
Height myHeight = Height(6, 3);
Height^ yourHeight = Height(70);
Height hisHeight = *yourHeight;
Console::WriteLine(L"My height is {0}", myHeight);
Console::WriteLine(L"Your height is {0}", yourHeight);
Console::WriteLine(L"His height is {0}", hisHeight);
return 0;
}
- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::結(jié)束==>> [Ex7_14.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
輸出為
My height is Height
Your height is Height
His height is Height
在上面的例子中,myHeight和hisHeight被分配在堆棧上,yourHeight被分配到了CLR堆上。其中hisHeight是yourHeight的一個(gè)副本,當(dāng)向 hisHeight賦值時(shí),需要用*操作符對句柄yourHeight進(jìn)行解除引用計(jì)算。這是因?yàn)?strong>數(shù)值類對象總是包含自己的數(shù)據(jù),因此它們不能引用同一個(gè)對象,在賦值時(shí)總是采用復(fù)制的方式進(jìn)行。注意:在C++/CLI中,不能重寫默認(rèn)構(gòu)造函數(shù)。默認(rèn)構(gòu)造函數(shù)將所有的值類型數(shù)據(jù)成員初始化為0,將引用類型(句柄)初始化為nullptr。同樣,也不能重載復(fù)制構(gòu)造函數(shù)和賦值操作符。默認(rèn)的復(fù)制操作是將每一個(gè)數(shù)據(jù)成員進(jìn)行復(fù)制,對象間的賦值也是如此。
C++/CLI中的類都有一個(gè)成員函數(shù)ToString(),它返回一個(gè)表示對象的字符串句柄。默認(rèn)情況下,該字符串為類名。這從上面的輸出可以看出:傳遞給WriteLine()函數(shù)的是Height對象,結(jié)果輸出的并非對象所包含的高度值,而是類名Height,這是因?yàn)榫幾g器認(rèn)為此處需要調(diào)用該對象的字符串表示法,因此安排的ToString()函數(shù)調(diào)用,這個(gè)過程可以顯示的表達(dá)為
double pi = 3.142;
Console::WriteLine(pi.ToString());
double類型被映射到System命名空間中的System::Double類,該類實(shí)現(xiàn)了ToString方法,因此可以正確的輸出變量pi的數(shù)值3.142而非類名Double。在上面的例子中,為了正確地輸出高度,可給Height定義中增加ToString()的重載函數(shù)。
//Create a string repesentation og the object
virtual String^ ToString() override
{
return feet + L" feet " + inches + L" inches";
}
現(xiàn)在可以正確的輸出為
My height is 6 feet 3 inches
Your height is 5 feet 10 inches
His height is 5 feet 10 inches
在定義數(shù)值類時(shí),如果數(shù)據(jù)成員為常量,C++/CLI中將其定義為”字面值”(literial)。在上面的例子中,將12定義為字面值,可以使得代碼的可讀性更高,避免“幻數(shù)”的出現(xiàn)(意指程序代碼中難以理解其來源或意義的常數(shù),如上面例子中的12)。定義字面值的方法如下
value class Height
{
int feet;
int inches;
literial int inchesPerFoot = 12;
// Other code...
};
這樣就可以在其后直接使用該字面值,而非難以理解的12了
Height(int ins)
{
feet = ins/ inchesPerFoot;
inches = ins% inchesPerFoot;
}
利用”字面值”leterial來定義常量的一個(gè)缺點(diǎn)是:必須在定義常量的同時(shí)指定它的值。另外一種定義常量的方法是使用initonly修飾符,使用該修飾符的常量變量只能在構(gòu)造函數(shù)的初始化表,或者構(gòu)造函數(shù)體內(nèi)進(jìn)行一次初始化, 之后再也不能被修改。注意:不能在聲明非靜態(tài)initonly常量時(shí)指定初值,而必須是在構(gòu)造函數(shù)的初始化表或構(gòu)造函數(shù)體內(nèi)。下面的例子描述了onlyinit的用法
value class Length
{
private:
int feet;
int inches;
public:
initonly int inchesPerFoot;
// Constructor
Length(int ft, int ins) :
feet(ft), inches(ins),
inchesPerFoot(12);
}
上面的構(gòu)造函數(shù)也可以寫成
Lenght(int ft, int ins) :
feet(ft), inches(ins)
{
inchesPerFoot = 12;
}
如果是靜態(tài)地initonly變量,則只能在定義時(shí)指定初值。因?yàn)槿绻詷?gòu)造函數(shù)中定義,則每次創(chuàng)建類實(shí)例都將對靜態(tài)變量賦值,這顯然與靜態(tài)、常量這樣的概念沖突。解決的辦法是,如果一定要在構(gòu)造函數(shù)中初始化initonly類型的靜態(tài)常量,則可定義一個(gè)靜態(tài)構(gòu)造函數(shù)。
value class Length
{
private:
int feet;
int inches;
static Length() { inchesPerFoot = 12; }
public:
initonly static int inchesPerFoot;
Length(int ft, int ins) :
feet(ft), inches(ins)
{ }
};
靜態(tài)構(gòu)造函數(shù)函數(shù)沒有形參,且沒有初始化表,總是被聲明為private。它不能被直接調(diào)用,而是由普通構(gòu)造函數(shù)在調(diào)用之前自動(dòng)調(diào)用。這種方法與在定義靜態(tài)initonly變量時(shí)指定初始值的唯一區(qū)別是,初始化值可以是在運(yùn)行時(shí)確定的。
二、定義引用類
引用類更加類似于本地C++類,它沒有數(shù)值類那么多的限制。但引用類沒有默認(rèn)的復(fù)制構(gòu)造函數(shù)和賦值運(yùn)算符,如果定義的類需要進(jìn)行復(fù)制或賦值,必須顯式地添加相應(yīng)的函數(shù)成員。下面的例子定義了一個(gè)引用類及其使用方法。
- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::開始==>> [Ex7_15.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ex7_15.cpp : main project file.
#include "stdafx.h"
using namespace System;
ref class Box
{
public:
// No-arg constructor supplying default field values
Box():Length(1.0), Width(1.0), Height(1.0)
{
Console::WriteLine(L"No-arg constructot called.");
}
// Constructor definition using an initialisation list
Box(double lv, double bv, double hv):Length(lv), Width(bv), Height(hv)
{
Console::WriteLine(L"Constructor called.");
}
// Function to calculate the volume of a box
double Volume()
{
return Length*Width*Height;
}
private:
double Length;
double Width;
double Height;
};
int main(array<System::String ^> ^args)
{
Box^ aBox;
Box^ newBox = gcnew Box(10, 15, 20);
aBox = gcnew Box;
Console::WriteLine(L"Default box volume is {0}", aBox->Volume());
Console::WriteLine(L"New box volume is {0}", newBox->Volume());
return 0;
}
- - - - - - - - - - - - - - - - <<== 華麗的分割線 ::結(jié)束==>> [Ex7_15.cpp] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
輸出為
Constructor called.
No-arg constructot called.
Default box volume is 1
New box volume is 3000
在上面的例子中,main()函數(shù)的第一句沒有創(chuàng)建任何對象,僅僅聲明了一個(gè)句柄,并被默認(rèn)的賦值成nullptr。此外,引用對象總是在堆上創(chuàng)建,因此總是用gcnew來調(diào)用其構(gòu)造函數(shù),并用句柄來跟蹤引用對象。