22、C++Primer 4 thノート、クラスタイプとクラスタイプからの変換
4026 ワード
1、変換はクラスタイプへの変換とクラスタイプからの変換の2種類に分けられます.クラスタイプへの変換:変換によって関数を構築します.クラスタイプからの変換:変換オペレータ.
2、よく使われる16個のオペレータ:5個の算術オペレータ(+、-、*、/、%)とそれに対応する複合賦値オペレータ、4個の関係オペレータ(<、<=、>、>=)、および等しいオペレータ(==、!=).
例
汎用形式:operator type();
typeは、組み込みタイプ名、クラスタイプ名、またはタイプ別名によって定義された名前を表します.関数として返されるタイプ(void以外)について、変換関数を定義できます.一般に、配列や関数タイプへの変換は許されず、ポインタタイプ(データや関数ポインタ)や参照に変換することはできます.
変換オペレータ関数はメンバー関数でなければなりません.戻りタイプを指定することはできません.パラメータテーブルは空でなければなりません.
クラスタイプ変換は転送できません(両方とも内蔵タイプのデフォルト変換ではなくカスタム変換です)、A->B、B->Cなどですが、Cタイプパラメータが必要な場所ではAタイプのパラメータを転送できません.
例
3、完全一致変換は標準変換が必要な他の変換より良い.
4、転換の二義性
例示的な二義性
二義性を回避する最良の方法は、互いに暗黙的な変換を提供するペアのクラスを記述することを回避することである.最大1つのパスだけが1つのタイプを別のタイプに変換することを保証します.
明示的に強制的に二義性を除去することができる.
例
リロード関数を呼び出す場合、コンストラクション関数または強制タイプ変換を使用して実パラメータを変換する必要があるのは拙劣な設計の表現です.
5、オペレータの再ロードの決定、三段階:
1)候補関数を選択します.
2)各実パラメータの潜在的な変換シーケンスを識別することを含む実行可能な関数を選択する.
3)最適に一致する関数を選択します.
6、いくつかの経験
1)相互変換のクラスを定義しないでください.すなわち、クラスFooがクラスBarを受け入れるオブジェクトのコンストラクション関数を持っている場合、クラスBarのタイプFooへの変換オペレータを定義しないでください.
2)組み込み算術タイプへの変換を避ける.具体的には、演算タイプへの変換が定義されている場合、
o算術タイプを受け入れるオペレータのリロードバージョンを定義しないでください.ユーザーがこれらのオペレータを使用する必要がある場合、変換オペレータは定義したタイプのオブジェクトを変換し、組み込みオペレータを使用できます.
o 1以上の算術タイプに変換する変換を定義しないでください.標準変換を他の算術タイプへの変換を提供します.
最も簡単なルールは、「明らかに正しい」場合は、変換関数の定義を避け、非明示的な構造関数を制限することです.
リファレンス
[1] http://blog.163.com/zhoumhan_0351/blog/static/3995422720103182106992/
[2] http://blog.163.com/zhoumhan_0351/blog/static/3995422720100284731826/
[3] http://blog.163.com/zhoumhan_0351/blog/static/3995422720104931348260/
2、よく使われる16個のオペレータ:5個の算術オペレータ(+、-、*、/、%)とそれに対応する複合賦値オペレータ、4個の関係オペレータ(<、<=、>、>=)、および等しいオペレータ(==、!=).
例
class SmallInt
{
public:
SmallInt(int i = 0):val(i)
{
//...
}
operator int() const {return val;} // , SmallInt int 。
private:
std::size_t val;
};
SmallInt si;
double dval;
si >= dval // si converted to int and then convert to double
if (si) // si converted to int and then convert to bool
汎用形式:operator type();
typeは、組み込みタイプ名、クラスタイプ名、またはタイプ別名によって定義された名前を表します.関数として返されるタイプ(void以外)について、変換関数を定義できます.一般に、配列や関数タイプへの変換は許されず、ポインタタイプ(データや関数ポインタ)や参照に変換することはできます.
変換オペレータ関数はメンバー関数でなければなりません.戻りタイプを指定することはできません.パラメータテーブルは空でなければなりません.
クラスタイプ変換は転送できません(両方とも内蔵タイプのデフォルト変換ではなくカスタム変換です)、A->B、B->Cなどですが、Cタイプパラメータが必要な場所ではAタイプのパラメータを転送できません.
例
class SmallInt
{
public:
SmallInt(int i = 0):val(i) //( )
{
//...
}
operator int() const {return val;} // , SmallInt int 。
private:
std::size_t val;
};
class Integral {
public:
Integral(int i = 0): val(i) { }
operator SmallInt() const { return val % 256; }
private:
std::size_t val;
};
int calc(int);
Integral intVal;
SmallInt si(intVal); // ok: convert intVal to SmallInt and copy to si
int i = calc(si); // ok: convert si to int and call calc
int j = calc(intVal); // error: no conversion to int from Integral
3、完全一致変換は標準変換が必要な他の変換より良い.
4、転換の二義性
例示的な二義性
#include "iostream"
#include "vector"
#include "algorithm"
#include "string"
#include "functional"
using namespace std;
class Integral;
class SmallInt
{
public:
SmallInt(Integral){}
//...
};
class Integral
{
public:
operator SmallInt() const{}
//...
};
void compute(SmallInt);
int main()
{
Integral int_val;
compute(int_val); //error:ambiguous
}
二義性を回避する最良の方法は、互いに暗黙的な変換を提供するペアのクラスを記述することを回避することである.最大1つのパスだけが1つのタイプを別のタイプに変換することを保証します.
明示的に強制的に二義性を除去することができる.
例
#include "iostream"
#include "vector"
#include "algorithm"
#include "string"
#include "functional"
using namespace std;
class SmallInt {
public:
// Conversions to int or double from SmallInt
// Usually it is unwise to define conversions to multiple arithmetic types
operator int() const { return val; }
operator double() const { return val; }
// ...
private:
std::size_t val;
};
void compute(int);
void compute(double);
void compute(long double);
int main()
{
SmallInt si;
//compute(si); // error: ambiguous
//compute(static_cast<int>(si)); //ok, call compute(int)
}
リロード関数を呼び出す場合、コンストラクション関数または強制タイプ変換を使用して実パラメータを変換する必要があるのは拙劣な設計の表現です.
5、オペレータの再ロードの決定、三段階:
1)候補関数を選択します.
2)各実パラメータの潜在的な変換シーケンスを識別することを含む実行可能な関数を選択する.
3)最適に一致する関数を選択します.
6、いくつかの経験
1)相互変換のクラスを定義しないでください.すなわち、クラスFooがクラスBarを受け入れるオブジェクトのコンストラクション関数を持っている場合、クラスBarのタイプFooへの変換オペレータを定義しないでください.
2)組み込み算術タイプへの変換を避ける.具体的には、演算タイプへの変換が定義されている場合、
o算術タイプを受け入れるオペレータのリロードバージョンを定義しないでください.ユーザーがこれらのオペレータを使用する必要がある場合、変換オペレータは定義したタイプのオブジェクトを変換し、組み込みオペレータを使用できます.
o 1以上の算術タイプに変換する変換を定義しないでください.標準変換を他の算術タイプへの変換を提供します.
最も簡単なルールは、「明らかに正しい」場合は、変換関数の定義を避け、非明示的な構造関数を制限することです.
リファレンス
[1] http://blog.163.com/zhoumhan_0351/blog/static/3995422720103182106992/
[2] http://blog.163.com/zhoumhan_0351/blog/static/3995422720100284731826/
[3] http://blog.163.com/zhoumhan_0351/blog/static/3995422720104931348260/