我正在实现一个智能指针类作为一个excerise。请考虑以下事项:
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;
}
答案 0 :(得分:4)
班级不同;你的构造函数是
my::Sptr<Base1>::Sptr(const my::Sptr<Derived>&)
并且您正在尝试访问my::Sptr<Derived>
的成员。
您需要声明模板朋友:
template<typename U> friend class Sptr;
答案 1 :(得分:4)
我指的是同一个类中的相同类变量。
不,你不是。也许你指的是同一个类模板的相同成员,我想像是
template <typename U>
Sptr(const Sptr<U> & other) : obj(other.obj), ref(other.ref) {}
但您不访问同一类的成员,因为Sptr<Base>
和Sptr<Derived>
是模板的不同实例,因此是不同的那些不能互相接触的阶级。
更新到您的修改:您现在获得的错误与访问权限无关,但它又与Sptr<Base>
和Sptr<Derived>
不同的类相关,因此指针它们是不同的指针类型,无法比较
对于相同的模板实例化(operator=
),您显示的代码为Sptr<T>
,但运算符中的错误发生在另一个模板实例化(Sptr<U>
)中。我猜你在那里也有地址比较,这是没有必要的,因为Sptr<T>
不能与Sptr<U>
具有相同的地址。
关于受保护~Base
的第二个错误显而易见:您使~Base
受保护且非虚拟化,意味着您不会通过删除Base
指针来销毁Base*
个对象。这同样适用于Base
的智能指针,因为它们会使用您禁止的多态删除。解决方案:将~Base
公开和虚拟。
答案 2 :(得分:2)
他们不是同一个班级。看起来它抱怨你试图从Sptr<Derived>
访问Sptr<Base1>
的成员 - 查看错误消息开头的类型变量实例化。
模板在填写类型变量时会生成看起来非常相似的全新类,因此MyClass<string>
与MyClass<vector<int>>
不同。