1

演習としてスマート ポインター クラスを実装しています。次の点を考慮してください。

class Base1 {
    protected:
        Base1() : derived_destructor_called(false) {
            printf("Base1::Base1()\n");
        }
    private:
        Base1(const Base1 &); // Disallow.
        Base1 &operator=(const Base1 &); // Disallow.
    protected:
        ~Base1() {
            printf("Base1::~Base1()\n");
            assert(derived_destructor_called);
        }
    protected:
        bool derived_destructor_called;
};

class Derived : public Base1 {
        friend void basic_tests_1();
    private:
        Derived() {printf("Derived::Derived()\n");}
        Derived(const Derived &); // Disallow.
        Derived &operator=(const Derived &); // Disallow.
    public:
        ~Derived() {
            printf("Derived::~Derived()\n");
            derived_destructor_called = true;
        }
        int value;
};

そして、次のテスト コード:

            Sptr<Derived> sp(new Derived);
            // // Test template copy constructor.
            Sptr<Base1> sp3(sp);

次のエラーが発生します。

Sptr.cpp: In instantiation of ‘my::Sptr<T>::Sptr(const my::Sptr<U>&) [with U = Derived; T = Base1]’:
Sptr.cpp:272:35:   required from here
Sptr.cpp:41:6: error: ‘Derived* my::Sptr<Derived>::obj’ is private
Sptr.cpp:117:86: error: within this context
Sptr.cpp:42:13: error: ‘my::RC* my::Sptr<Derived>::ref’ is private
Sptr.cpp:117:86: error: within this context
Sptr.cpp:43:31: error: ‘std::function<void()> my::Sptr<Derived>::destroyData’ is private
Sptr.cpp:117:86: error: within this context

これはどのように可能ですか?同じクラス内の同じクラス変数を参照しています。

以下は、コンストラクター宣言を含むテンプレート クラス プロトタイプです。

template <class T>
class Sptr {
private:
    //some kind of pointer
        //one to current obj
    T* obj;
    RC* ref;
    std::function<void()> destroyData;
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;};

    //operator unspecified_bool_type() const;

    //overload *,->,=,copy-constructor

    // const-ness should be preserved.
    // Test for null using safe-bool idiom
    // Static casting, returns a smart pointer
};

編集

テンプレート クラス内で次のようにテンプレート フレンドを宣言しました。

template<typename U> friend class Sptr;

それは上記のエラーを解決しました。しかし、それは新しいエラーを生み出しました!

テストコード:

        Sptr<Base1> sp2;
        {
            Sptr<Derived> sp(new Derived);
            // // Test template copy constructor.
            Sptr<Base1> sp3(sp);
            sp2 = sp;
            sp2 = sp2;
        }

エラー:

Sptr.cpp: In instantiation of ‘my::Sptr<T>& my::Sptr<T>::operator=(const my::Sptr<U>&) [with U = Derived; T = Base1]’:
Sptr.cpp:274:23:   required from here
Sptr.cpp:128:9: error: comparison between distinct pointer types ‘my::Sptr<Base1>*’ and ‘const my::Sptr<Derived>*’ lacks a cast
Sptr.cpp:212:9: error: ‘Base1::~Base1()’ is protected
Sptr.cpp:132:21: error: within this context
Sptr.cpp: In instantiation of ‘my::Sptr<T>& my::Sptr<T>::operator=(const my::Sptr<T>&) [with T = Base1]’:
Sptr.cpp:275:23:   required from here
Sptr.cpp:212:9: error: ‘Base1::~Base1()’ is protected
Sptr.cpp:154:21: error: within this context

すでにテンプレートの友達になっているのに、これはどのように可能ですか? = 演算子の下でオーバーロード

template <typename T> 
Sptr<T>& Sptr<T>::operator=(const Sptr<T> &t) {

    std::cout<<"= const <T>\n";
    if(this != &t) {
        if(ref->Release() == 0) {

            if(obj)
                delete obj;

            delete ref;       
        }

        obj = t.obj;
        ref = t.ref;
        destroyData = t.destroyData;
        ref->AddRef();
    }

    return *this;
}
template <typename T> 
template <typename U> 
Sptr<T>& Sptr<T>::operator=(const Sptr<U> &t) {

    std::cout<<"= const <U>\n";
    if(this != &t) {
        if(ref->Release() == 0) {

            if(obj)
                delete obj;

            delete ref;       
        }

        obj = t.obj;
        ref = t.ref;
        destroyData = t.destroyData;
        ref->AddRef();
    }

    return *this;
}
4

3 に答える 3