0

これが私のクラス宣言です:

template <class T>
class Sptr {
    template<typename U> friend class Sptr;

    template <typename T1, typename T2>
    friend bool operator==(const Sptr<T1> &a, const Sptr<T2> &b);

    template <typename U>
    friend Sptr<T> static_pointer_cast(const Sptr<U> &sp);

private:

    RC* ref; //reference counter
    T* obj;//pointer to current obj
    std::function<void()> destroyData;

    bool ok_;

public:

    Sptr();
    ~Sptr();

    template <typename U> 
    Sptr(U *);

    Sptr(const Sptr &);

    template <typename U> 
    Sptr(const Sptr<U> &);

    template <typename U> 
    Sptr<T> &operator=(const Sptr<U> &);

    Sptr<T> &operator=(const Sptr<T> &);

    void reset();

    T* operator->() const
    {return obj;};

    T& operator*() const
    {return *obj;};

    T* get() const
    {return obj;};

    explicit operator bool() const {
          return ok_;
    }

};

以下は、アクセスの問題を訴えるコードです

    template <typename T, typename U>
Sptr<T> static_pointer_cast(const Sptr<U> &sp) {
    //do something
    Sptr<U> answer;

    answer.obj = sp.obj;
    answer.ref = sp.ref;
    answer.destroyData = sp.destroyData;
    answer.ok_ = sp.ok_;

    return answer;
}

次のコードでコンパイルすると:

    Sptr<Derived> sp(new Derived);
    Sptr<Base1> sp2(sp);

    // Sptr<Derived> sp3(sp2); // Should give a syntax error.
    Sptr<Derived> sp3(static_pointer_cast<Derived>(sp2));
    // Sptr<Derived> sp4(dynamic_pointer_cast<Derived>(sp2)); // Should give syntax error about polymorphism.

すでにフレンド機能にしています。変数にアクセスできない理由とその修正方法は?

4

2 に答える 2

2

これは少しトリッキーです。置き換えるとコードがコンパイルされます

template <typename U>
friend Sptr<T> static_pointer_cast(const Sptr<U> &sp);

template <typename T1, typename T2>
friend Sptr<T1> static_pointer_cast(const Sptr<T2> &sp);

理由は次のとおりです(100%確信があるわけではないので、誰か承認/却下してください):

Sptr<T>インスタンス化されると (たとえば でT = Derived)、結果のクラス定義 ( Sptr<Derived>) は、次のシグネチャを持つフレンド関数を定義します。

template <typename U>
friend Sptr<Derived> static_pointer_cast(const Sptr<U> &sp);

したがって、これはテンプレート パラメータが1 つしかない関数です。しかし、定義した関数には2 つのテンプレート パラメーターがあります。

このテンプレート化された関数への呼び出しは、次のような特殊化です。

Sptr<Derived> static_pointer_cast(const Sptr<Base1> &sp) {
    //do something
    Sptr<Derived> answer;

    answer.obj = sp.obj;
    answer.ref = sp.ref;
    answer.destroyData = sp.destroyData;
    answer.ok_ = sp.ok_;

    return answer;
}

したがって、 との両方 Base1 Derivedアクセスしようとしますが、 のフレンドではなくのフレンドにすぎDerivedませんBase1この最後の文が重要で、 2 つのテンプレート パラメータを持つフレンド関数に変更すると、この問題は解決します。

于 2013-04-18T00:26:06.553 に答える
1

あなたは友人とsptr<t>言いました。つまり、同じタイプの sptrs のプライベートメンバーにのみアクセスできます。sp2 は sptr ( t が派生) ではないため、フレンドではありません。試す :

template< class u, class v> friend sptr<u> static_pointer_cast(const sptr<v> &sp);
于 2013-04-18T00:33:30.287 に答える