C++ピックアップ-クラス構造関数の暗黙的な変換

2869 ワード

前にC++を批判する文章を見たことがありますが、大体は「奇技淫巧」が多すぎて、良い言語ではありません.私はこの「奇技淫巧」の描写に興味を持っています.批判者の話によると、C++のいくつかの特性はちょうど技術を誇示する同級生に自慢の資本を持つことができます.結局、誰もが知っているものは自慢することはありません.「孔乙己」の「回」について、いくつかの書き方があることを思い出す.その时、先生はこの授业の时、批判的な态度を持って孔乙己のこのような思想を评価して、私はこの中にきっといくつかの面白い文化があることを感じています——もしかすると“回”の字の変化の过程は何を说明することができます.だから「回」の字に関する内容は孔乙己が純粋でかわいい人だと感じさせた.(転載breaksoftwareからのcsdnブログを明記してください)
このシリーズのブログを書くのは、私がC++を批判したいわけではないし、弁護したいわけでもない.ただ面白いものを羅列したいだけなので、名前をつけて面白いものを拾います.
まず、クラス構造関数の暗黙的な変換という比較的一般的な技術を見てみましょう.ここでは先に説明しますが、その後の例では、できるだけ主な内容を強調するために、十分な条件として必要ではない条件であるものを無視するので、設計されたコードの中には「不完全」の疑いがあります.すべての脆弱性を塞ぐために、コード全体が私が紹介したい技術ではなく、「苦行僧」式のプログラミングの原則に重点を置いているように感じられることが多いからです.
C++は次の関数のような厳格な言語であることを知っています.
void test_int_proxy(const int_proxy& v) {
    printf("%d", v.value());
}
呼び出し者は、その参照もint_であるべきである.Proxyのオブジェクトですが、実際の状況はそうではありません.では、どのように表現すればいいのか、個人的には、コンパイラがそのパスをint_であるべきだと思います.proxyオブジェクト.この2つの表現の違いは、「呼び出し者」と「コンパイラ」の違いです.実際の例を見てみましょうintを仮定しますProxyクラスは次のように定義されています.
class int_proxy {
public:
    int_proxy(int n) : _m(n) {};
public:
    int value() const {
        return _m;
    }
private:
    int _m;
};
クラスは非常に簡単で、パラメータ付き構造関数を持ち、パラメータリスト形式でクラスのメンバー変数を初期化します.
一般的にtestを呼び出すint_proxyメソッド:
    test_int_proxy(int_proxy(100));
という書き方に異論はないと思いますが、次のような書き方が出てくると納得できないかもしれません.
    test_int_proxy(100);
しかし、この書き方は上記のクラスの定義にとって合法的です!その効果とint_の使用proxy制御は同じです.これはなぜですか.これがクラス構造関数の暗黙的な変換技術である.C++コンパイラはtest_int_Proxyメソッドはconstタイプのint_を伝達するはずですProxyオブジェクトですが、パラメータがオブジェクトではないことが分かった場合、クラスでこのパラメータを使用してオブジェクトを構築できる方法で一時的なオブジェクトを構築します.我々の例では、参照100はint型データであり、int_Proxyにはintパラメータを持つ構造関数がちょうどあります.クラス構造関数の暗黙的な変換に必要な条件を少しまとめます.
  • パラメータタイプに厳密に対応する関数が見つからない
  • は、パラメータタイプが厳密に一致するクラスの構造関数
  • を見つける.
  • 暗黙変換は一時的なオブジェクトを構成するので変更できないため、暗黙変換をトリガする関数のパラメータタイプはconst修飾
  • を使用する必要がある.
    しかし、個人的にはこのような「奇抜な淫技」は使わないほうがいいと思います.たとえば、コードには次の関数があります.
    void test_int_proxy(const int& v) {
        printf("%d", v + 100);
    }
    では、C++コンパイラは、パス100の呼び出しに対して上記の手順を実行します.このような関数呼び出しには2つの一致する呼び出し方法があり、不確実性が発生します.ここでは、コンパイラがどの方法を呼び出すかの不確実性ではなく、このコードを維持している人が上記のコードを調整するときに、いくつかの問題を無視しやすいことによる「人災」を指します.
    たとえば、コードに次のクラスとメソッドを追加します.
    class int_proxy_2 {
    public:
        int_proxy_2(int n) : _m(n) {};
    public:
        int value() const {
            return _m + 100;
        }
    private:
        int _m;
    };
    
    void test_int_proxy(const int_proxy_2& v) {
        printf("%d", v.value());
    }
    では、コンパイラは、暗黙的な変換がどのクラスを変換するかを決定することができず、どのtestを呼び出すか分からない.int_proxyメソッドです.
    クラスコンストラクタの暗黙的な変換を制限する方法も簡単です.対応するコンストラクタにexplictキーワードを付けることです.
    class int_proxy {
    public:
        explicit int_proxy(int n) : _m(n) {};
    のように暗黙的な変換によって一時的なオブジェクトを構築する計画は、察知され、禁止されるであろう.