C++-使用類(類的自動轉換和強制型別轉換)
使用類-類的自動轉換和強制型別轉換
可以將類定義成與基本型別或另一個類相關,使得從一種型別轉換為另一種型別是有意義的。 在這種情況下,程式設計師可以指示C++如何自動進行轉換,或通過強制型別轉換來完成。
(1) stonewt.h
//stonewt.h #ifndef STONEWT_H_ #define STONEWT_H_ class Stonewt { private: enum { Lbs_per_stn = 14 }; //一英石=14磅 int stone; double pds_left; double pounds; public: Stonewt(double lbs); //double型別磅的建構函式 Stonewt(int stn, double lbs); //英石、磅的建構函式 Stonewt(); ~Stonewt(); void show_lbs() const; //用磅格式顯示重量 void show_stn() const; //用英石格式顯示重量 }; #endif // !STONEWT_H_
(2) stonewt.cpp
//stonewt.cpp #include<iostream> using std::cout; #include"stonewt.h" //double值的Stonewt物件建構函式 Stonewt::Stonewt(double lbs) { stone = int(lbs) / Lbs_per_stn; pds_left = int(lbs) % Lbs_per_stn+lbs - int(lbs); pounds = lbs; } //英石、double值的Stonewt物件建構函式 Stonewt::Stonewt(int stn, double lbs) { stone = stn; pds_left = lbs; pounds = stn * Lbs_per_stn + lbs; } Stonewt::Stonewt() { stone = pounds = pds_left = 0; } Stonewt::~Stonewt() { } //用英石顯示重量 void Stonewt::show_stn() const { cout << stone << " stone," << pds_left << " pounds\n"; } //用磅顯示重量 void Stonewt::show_lbs() const { cout << pounds << " pounds\n"; }
在C++中,接受一個引數的建構函式為將型別與該引數相同的值轉換為類提供了藍圖。 因此,下面的建構函式用於將double型別的值轉換為Stonewt型別:
Stonewt(double lbs); //double-Stonewt型別轉換的模板
也就是說,可以編寫這樣的程式碼:
StonewtmyCat; //建立一個Stonewt物件
myCat =19.6; //用Stonewt(double)將19.6轉換為Stonewt型別
只有接受一個引數的建構函式才能作為轉換函式。
C++新增了關鍵字explicit,用於關閉這種自動特性。 也就是說,可以這樣宣告建構函式:
explicit Stonewt(double lbs); //不允許隱式轉換
這將關閉上述示例中介紹的隱式轉換,但仍然允許顯示轉換,即顯式強制型別轉換:
StonewtmyCat; //建立一個Stonewt物件
myCat = 19.6; //如果Stonewt(double)被宣告為explicit則無效
mycat = Stone(19.6); //可以,顯式轉換
mycat =(Stonewt) 19.6; //可以,老式顯式轉換
(3) stone.cpp
//stone.cpp
#include<iostream>
using std::cout;
#include"stonewt.h"
void display(const Stonewt & st, int n);
int main()
{
Stonewt incognito = 275; //使用建構函式初始化
Stonewt wolfe(285.7); //和Stonewt wolfe=285.7相同
Stonewt taft(21, 8);
cout << "The celebrity weighed ";
incognito.show_stn();
cout << "The detective weighed ";
wolfe.show_stn();
cout << "The president weighed ";
taft.show_lbs();
incognito = 276.8; //使用建構函式進行轉換
taft = 325; //和taft = Stonewt(325)相同
cout << "After dinner, the celebrity weighed: ";
incognito.show_stn();
cout << "After dinner, the president weighed: ";
taft.show_lbs();
display(taft, 2);
cout << "The wrestler weighed even more.\n";
display(422, 2); //將422轉換為double型別,進而轉換為Stonewt型別
cout << "No stone left unearned\n";
std::cin.get();
return 0;
}
void display(const Stonewt& st, int n)
{
for (int i = 0; i < n; i++)
{
cout << "Wow! ";
st.show_stn();
}
}
當建構函式只接受一個引數時,可以使用下面的格式來初始化物件:
//當使用帶有一個引數的建構函式初始化一個類物件時的語法
Stonewtincognito = 275;
這等價於前面介紹過的另外兩種格式:
//初始化類物件的標準語法
Stonewt incognito(275);
Stonewt incognito = Stonewt(275);
然而,後兩種格式可用於接受多個引數的建構函式。
最後,請注意下面的函式呼叫:
display(422,2); //將422轉換為double型別,進而轉換為Stonewt型別
display()原型表明,第一個引數應是Stonewt物件。 遇到int引數時,編譯器查詢建構函式Stonewt(int),以便將該int轉換為Stonewt型別。 由於沒有找到這樣的建構函式,因此編譯器尋找接受其他內建型別(int可以轉換為這種型別)的建構函式。Stone(double)建構函式滿足這種條件,因此編譯器將int轉換為double,然後使用Stonewt(double)將其轉換為一個Stonewt物件。
(4) 轉換函式
建構函式只用於從某種型別到類型別的轉換。 要進行相反的轉換,必須使用特殊的C++運算子函式——轉換函式。
轉換函式是使用者定義的強制型別轉換,可以像使用強制型別轉換那樣使用它們。 例如,如果定義了從Stonewt到double的轉換函式,就可以使用下面的轉換:
Stonewtwolfe(285.7);
double host = double(wolfe); //語法#1
double thinker = (double)wolfe; //語法#2
也可以讓編譯器來決定如何做:
Stonewtwells(20, 3);
double star = wells; //轉換函式的隱式呼叫
編譯器發現,右側是Stonewt型別,而左側是double型別,因此它將檢視程式設計師是否定義了與此匹配的轉換函式。(如果沒有找到這樣的定義,編譯器將生成錯誤訊息,指出無法將Stonewt賦給double。)
要轉換為typeName型別,需要使用這種形式的轉換函式:
operator typeName();
注意:
轉換函式必須是類方法;
轉換函式不能指定返回型別;
轉換函式不能有引數。
要新增將stonewt物件轉換為int型別和double型別的函式,需要將下面的原型新增到類宣告中:
operatorint();
operatordouble();
stonewt1.h
//stonewt1.h
#ifndef STONEWT_H_
#define STONEWT_H_
class Stonewt
{
private:
enum { Lbs_per_stn = 14 }; //一英石=14磅
int stone;
double pds_left;
double pounds;
public:
Stonewt(double lbs); //double型別磅的建構函式
Stonewt(int stn, double lbs); //英石、磅的建構函式
Stonewt();
~Stonewt();
void show_lbs() const; //用磅格式顯示重量
void show_stn() const; //用英石格式顯示重量
//轉換函式
operator int() const;
operator double() const;
};
#endif // !STONEWT_H_
(5) stonewt1.cpp
//stonewt1.cpp -- Stonewt類方法+轉換函式
#include<iostream>
using std::cout;
#include"stonewt1.h"
//double值的Stonewt物件建構函式
Stonewt::Stonewt(double lbs)
{
stone = int(lbs) / Lbs_per_stn;
pds_left = int(lbs) % Lbs_per_stn+lbs - int(lbs);
pounds = lbs;
}
//英石、double值的Stonewt物件建構函式
Stonewt::Stonewt(int stn, double lbs)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
Stonewt::Stonewt()
{
stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt()
{
}
//用英石顯示重量
void Stonewt::show_stn() const
{
cout << stone << " stone," << pds_left << " pounds\n";
}
//用磅顯示重量
void Stonewt::show_lbs() const
{
cout << pounds << " pounds\n";
}
//轉換函式
Stonewt::operator int() const
{
return int(pounds + 0.5);
}
Stonewt::operator double() const
{
return pounds;
}
(6) stone1.cpp
程式stone1.cpp對新的轉換函式進行測試。 該程式中的賦值語句使用隱式轉換,而最後的cout語句使用顯式強制型別轉換。
//stone1.cpp
#include<iostream>
#include"stonewt1.h"
void display(const Stonewt & st, int n);
int main()
{
using std::cout;
Stonewt poppins(9, 2.8); //9英石,2.8磅
double p_wt = poppins; //隱式轉換
cout << "Convert to double => ";
cout << "Poppins: " << p_wt << " pounds.\n";
cout << "Convert to int => ";
cout << "Poppins: " << int(poppins) << " pounds.\n";
std::cin.get();
return 0;
}
(7) 轉換函式和友元函式
下面為Stonewt類過載加法運算子。
假設沒有定義operator double()轉換函式。 可以使用下面的成員函式實現加法。
Stonewt Stonewt::operator+(const Stonewt & st) const
{
double pds = pounds + st.pounds;
Stonewt sum(pds);
return sum;
}
也可以將加法作為友元函式來實現,如下所示:
Stonewt operator+(const Stonewt & st1,const Stonewt & st2)
{
double pds = st1.pounds+st2.pounds;
Stonewt sum(pds);
return sum;
}
可以提供方法定義或友元函式定義,但不能都提供。 上面任何一種格式都允許這樣做:
StonewtjennySt(9, 12);
StonewtbennySt(12, 8);
Stonewt total;
total =jennySt + bennySt;
另外,如果定義了Stonewt (double)函式,則也可以這樣做:
StonewtjennySt(9, 12);
double kennyD= 176.0;
Stonewt total;
total =jennySt + kennyD;
但只有友元函式才允許這樣做:
StonewtjennySt(9, 12);
double pennyD= 146.0;
Stonewt total;
total =pennyD + jennySt;
這裡的經驗是,將加法定義為友元函式可以讓程式更容易適應自動型別轉換。
相關程式設計練習題請參考: