3

次の 2 つのユースケースの動作が異なるのはなぜですか?

組み込み型の例:

class Test
{
    operator const char*() {
        return "operator const char*() called";
    }

    operator char*() {
        return const_cast<char*> ("operator char*() called");
        // a really ugly hack for demonstration purposes
    }
};

Test test;
const char *c_ch = test;  // -> operator const char*() called
char *ch = test;          // -> operator char*() called

さて、すべてが正常に機能します。いいえ、ユーザー定義型で試してみましょう:

class ColorWrapper
{
    operator const Color() {
        cout << "operator const Color() called" << endl;
        return Color(10, 20, 30);
    }

    operator Color() {
        cout << "operator Color() called" << endl;
        return Color(11, 22, 33);
    }
};

ColorWrapper cw;
const Color c_col = cw;
Color col = cw;

状況は同じように見えます。しかし今、GCCは不平を言い始めます:

error: conversion from 'ColorWrapper' to 'const Color' is ambiguous
error: conversion from 'ColorWrapper' to 'Color' is ambiguous

何か不足していますか?ここで達成しようとしているのは、ユーザーが直接色を変更できないようにすることです。変更したい場合は、ラッパー クラスを介して行う必要があります。

4

4 に答える 4

3

問題は、2つの例が同等ではないということです。1つ目は、コンパイラが簡単に選択できる2つの異なるタイプ、可変データへのポインタと定数データへのポインタを返します。ポインタ定数ポインタの場合は異なります(つまり、ポイントされたデータを変更しないのとは対照的に、返されたポインタが指す場所を変更することはできません)。

class Test
{
    operator char * const();
    operator char *();
};

これは2番目の例と同等であり、同じあいまいさをもたらします。コンパイラはどちらを選択するかを決定できないため、どちらも同じ型を返し、一方はconst-qualifiedで、もう一方はそうではありません。

これは、オブジェクトの恒常性に基づいてオーバーロードすることで解決できます。

class ColorWrapper
{
    operator const Color() const;
    operator Color();
};

ただし、とにかく値で新しいオブジェクトを返すため、ここでは何も購入しません。したがって、いつでもconstバージョンを返すことができます。また、宛先オブジェクトのconstnessではなく、ソースオブジェクトのconstnessに基づいて適切なバージョンが選択されます(したがって、どちらの場合も非constバージョンを呼び出します)。これは、希望どおりではないようです。

したがって、ソースオブジェクトの定数に基づいてオーバーロードできます。しかし、今のように、宛先オブジェクトの定数に基づいて単純にオーバーロードすることはできません。

これはすべて、オブジェクトとオブジェクトが誤って参照する可能性のあるデータとの違いについて考えることになります。これは、実際には、定数ポインターと定数データへのポインターの違いとして現れます。

ここで私が達成しようとしているのは、ユーザーが直接色を変更できないようにすることです

そうすれば、オーバーロードの必要はまったくありません。constバージョンを返すだけです。ユーザーは返された色を直接変更することはできません。ユーザーはそれをコピーして変更することしかできません。

cw.set(red);    //nope, return color is constant
Color col = cw; //copy returned color into col
col.set(green); //fine, since we're not working on the returned color, but on col

const Color c_col = cw; //use this if you don't want c_col to be modified, 
                        //doesn't have anything to do with returned color, though
于 2012-10-16T13:24:14.463 に答える
2

これは、2 番目の例では const を object に追加していたためです (最初のケースでは)。また、const with object make compile は、オーバーロードの解決段階で混乱します。これら 2 つは、c++ 標準に従って、互いに同等です (オブジェクトと const オブジェクト)。コンパイラは、ここで賢くしようとせず、別のものを選択します。

しかし、ポインターと const ポインター (参照も機能します) では、コンパイルはこれら 2 つのオーバーロード候補から適切に選択できます。これが最初のケースです。

于 2012-10-16T12:55:25.570 に答える
0

1つの演算子をに変更するとconst、次のように機能します。

operator const Color() const {
    cout << "operator const Color() const called" << endl;
    return Color(10, 20, 30);
}

または、2つの演算子のいずれかを削除することもできます。by値を返すためColor、2つの演算子の間に実際の違いはありません。

于 2012-10-16T12:48:33.433 に答える
0

ここでは基本的に 2 つの異なるケースがあるため、この問題が発生します。ここで何が起こっているかを示す最も簡単な方法は、最初の例を少し変更することだと思います。

class Test
{
    operator char* const() {
        return "operator char* () called";
    }

    operator char*() {
        return const_cast<char*> ("operator char*() called");
        // a really ugly hack for demonstration purposes
    }
};

これで、2 番目の例とまったく同じ状況になります。基本的に、(ポインターの) コピーと const コピーを返すため、オーバーロードの解決で混乱します。

元の最初の例は、これらの変換演算子が 2 つの異なる型 (const charおよびchar) のポインターに変換されるため、正常に機能します。ここで違いを理解するのに役立つことを願っています。

ところで、私は個人的に、メソッドから const コピーを返すことにあまり意味がないと信じています。ユーザーには何も変更せず、クラス インターフェイスを難読化するだけです。

于 2012-10-16T13:44:55.360 に答える