1

質問:const参照がパブリックに返され、non const参照がプライベートに返されるようにするにはどうすればよいですか?

クラス内のいくつかの変数の読み取り専用テンプレートを作成しようとしています。これには、公開時にデータへのconst参照を返すテンプレートクラスが含まれます。ただし、クラスではデータを操作する必要があるため、個人的にconstではない参照を返そうとしています。基本は次のとおりです。

private: operator T&() { return data; }
public: operator const T&() const { return data; }

上記のように非const参照を追加すると、変数にパブリックにアクセスしようとすると、Visual Studio 2010 cl.exeコンパイラは、クラスのプライベートメンバーにアクセスできないと通知します。cout << myobj.x << endlテンプレートを使用してxが宣言されたかのような単純なものは失敗します。

error C2248: 'proxy<T,C>::operator int &' : cannot access private member declared in class 'proxy<T,C>'

参考のために他のスレッドを次に示します
。C++-VisualStudio2010で読み取り専用のクラスメンバー変数を作成する方法-StackOverflow

編集:あなたはコードを要求したので、ここにあります。

template <class T, class C>
class proxy {
    friend C;
private:
    T data;
    T operator=(const T& arg) { data = arg; return data; }
    operator T&() { return data; } // I'd expect this is only returned privately
public:
    operator const T&() const { return data; }
};

class myClass {
public:
    proxy<int,myClass> x;

    void f(int i) {
        x = i;
    }
};

int main(int argc, char **argv)
{
    myClass test;
    test.f(12);
    cout << test.x << endl; // Compiler error trying to access non-const T&
    return 0;
}
4

3 に答える 3

2

実際、可視性アクセシビリティは C++ では独立したものです。

  • 可視性ルールは、オーバーロードを解決するときにすべてのメンバー関数が考慮されることを示しています。
  • アクセシビリティとは、選択したオーバーロード関数が使用されているコンテキスト (クラスの外部からのプライベート メンバーなど) からアクセスできない場合、コンパイラ エラーが発生することを意味します。

関数がクラスの外部から呼び出された場合、プライベート メンバーはオーバーロードの解決に参加しないと考える人もいますが、そうではありません。アクセスに関係なく、すべての機能が考慮されます。

特定の問題について、次のことを行います。

std::cout << test.x;

testこれは非 const であり、 もそうでtest.xあり、2 つのオーバーロード変換関数のうち、非 const が選択されます。しかし、残念ながら、この関数は非公開であるため、コンパイラ エラーが発生します。

簡単な解決策は、次のことを行うことですconst_cast

std::cout << const_cast<const myClass&>(test).x;

または、必要に応じて:

const myClass &ctest = test;
std::cout << ctest.x;

正しい解決策は、const 以外のプライベートなものを削除することです。dataクラスコンテキストからメンバーを直接使用できるため、必要ありません。

率直に言って、他の言語の構文を使用して C++ でプロパティを実装しようとしているようです。プロパティは問題ありませんが、それは C++ のやり方ではありません。

私のアドバイスは次のとおりです。言語と争うのではなく、構文をそのまま受け入れ、かっこを使用するだけです。またはx、不変条件を保持していない場合は、公開してください。

最短の方法は次のようになります。

class myClass {
private:
    int _x;
public:
    int x() const {
        return _x;
    }
    //if needed
    void x(int value) {
        _x = value;
    }
};

将来あなたのコードを読む人 (私かもしれません!) は、あなたが言語を再発明しようとしないことを高く評価するでしょう。

于 2012-09-03T19:18:30.033 に答える
1

C++ では、オーバーロードの解決後にアクセス チェックが行われます。これには、アクセスできない関数を候補セットから削除するという他の可能性よりも利点と欠点の両方があります。

通常、解決策はプライベート関数に別の名前を使用することです。しかし、友達になったいくつかの機能に必要な特定のインターフェースに準拠しようとしているようです。そのための簡単な回避策はないと思います。継承された関数は候補セットの一部ではなく、派生クラスの関数によって隠されているため、一般的なケースではプライベート継承は役に立ちません。しかし、変換関数は継承されています...そしてテスト後、元の問題が再発するようです (プライベート基本クラスでのプライベート変換も見つかります)。

したがって、次のように、変換の代わりに名前付き関数を使用することを最終的に提案します。

template <typename T, typename C>
class proxy
{
    friend C;
private:
    T data;
    T operator=(const T& arg) { data = arg; return data; }
    T& mutate() { return data; }
public:
    operator const T&() const { return data; }
};

class myClass
{
public:
    proxy<int,myClass> x;

    void f(int i)
    {
        x.mutate() = i;
    }
};
于 2012-09-03T19:19:10.500 に答える
0

testは const ではありません、const ではtest.xありません。myClass::operator int()myClass::operator int() const

アクセス制御(private/public)は入りません。

于 2012-09-03T18:47:51.207 に答える