根据我以前的question,我希望boost::shared_ptr<A>
实际上是A
(或许A*
)的子类,以便它可以用于采用的方法中A*
作为他们的论点。
考虑以下课程:
class A
{
public:
A(int x) {mX = x;}
virtual void setX(int x) {mX = x;}
virtual int getX() const {return mX;}
private:
int mX;
};
在上一个问题中,我提议创建一个SharedA对象来处理这个问题,并且可能是这样做的。
class SharedA : public A
{
public:
SharedA(A* a) : mImpl(a){}
virtual void setX(int x) {mImpl->setX(x);}
virtual int getX() const {return mImpl->getX();}
private:
boost::shared_ptr<A> mImpl;
};
如果我可以创建一个模板类来为我处理所有这些问题,那将是Grrrrrrrrreat想的。
template <class T>
class Shared : public T
{
public:
SharedT(T* t) : mImpl(t)
{
//What kind of crazy voodoo goes here?
}
private:
boost::shared_ptr<T> mImpl;
};
如果我有这个,(以及Shared<T>
中的正确构造函数),那么我可以执行以下操作:
A* indestructo_A = new Shared<A>(new A(100));
A* indestructo_A_clone = new Shared<A>(indestructo_A);
delete indestructo_A
cout << "Indestructo-A back with a vengence!" << indestructo_A_clone.getX();
问题:
这有用吗?或者它的实用程序仅适用于处理特别糟糕代码的极端情况。例如:
void aFunctionYouHaveToUse(A * a)
{
/ 一些有用的算法然后 /
删除一个;
}
是否可以构建这样的模板类? (我猜你需要反思,对吗?)如果你能建造它,怎么做?
答案 0 :(得分:8)
有一个非常好的理由,为什么shared_ptr不允许显式转换为A *(有更好的方法来做它而不是继承,这无论如何都是不可能的)。 shared_ptr和其他智能指针的全部目的是提供一个小的封装对象,其唯一目的是拥有一个指针并决定何时以及如何删除它。
如果这个对象允许同样的指针只是狡猾地传递,没有想到,那么它根本无法达到它的目的。每当你深入了解智能指针以获取内部的原始指针时,都会违反其所有权语义,然后必须小心谨慎,不要做一些愚蠢的事情。智能指针会让你想到这一点,强迫你调用指针进入内部,而不是只是在你不小心将它传递给错误的函数时默默地这样做。想想它就像智能指针一样,“嘿,你知道你在做什么可能很危险,对吧?好吧,你走了。”
恕我直言,如果共享指针不允许访问指针,宇宙将是一个更好的地方。不幸的是,这不是这个宇宙,也不可能是这个宇宙,因为偶尔你仍然需要将这个东西传递给一个不使用智能指针的函数。所以,既然我们不是生活在那个更好的宇宙中,那么我们的智能指针确实允许访问,它们只是不容易接触它。答案 1 :(得分:1)
也许有一种方法,但它是一种肮脏的方式。您可以尝试在层次结构中放置另一个类:ABase。 A可以继承自ABase,而ABase将包含所有公共方法的默认实现。像这样:
#include <iostream>
#include <boost/shared_ptr.hpp>
class ABase
{
public:
ABase() {}
void init( ABase *a ) { mImpl.reset( a ); }
virtual void setX( int x ) { mImpl->setX( x ); }
virtual int getX() const { return mImpl->getX(); }
boost::shared_ptr< ABase > mImpl;
};
class A : public ABase
{
public:
typedef ABase BaseClass;
A(int x) {mX = x;}
virtual void setX(int x) {mX = x;}
virtual int getX() const {return mX;}
private:
int mX;
};
template <class T>
class Shared : public T::BaseClass
{
public:
Shared(T* t) { init( t ); }
};
int main()
{
Shared< A > sh( new A( 1 ) );
std::cout << sh.getX() << std::endl;
sh.setX( 5 );
std::cout << sh.getX() << std::endl;
}
这只是一个概念。我需要验证代码。关键的想法是通过继承共享而不是直接从类型A传递默认实现,而是从他的基本类型继承,它具有所需的所有实现。基类需要更多的工作,但我认为这个想法很清楚。
它不完全是你所要求的(实际上是不可能的),但它在某些情况下可能很有用,而且可能是最接近的。
答案 2 :(得分:0)
不管这是不是一个好主意。如果你想要一个可以隐式转换为原始指针的共享指针类型,你不需要继承指针类型或者经历其他类似的复杂问题。只需使用适当的隐式转换运算符创建共享指针类型。
这可以通过继承或现有共享指针类型的组合来完成。 (或者从头开始创建自己的共享指针)。
使用继承,例如:
template<typename T>
class convertible_shared_ptr : public boost::shared_ptr<T>
{
public:
convertible_shared_ptr() {}
convertible_shared_ptr(T* ptr) : boost::shared_ptr<T>(ptr) {}
operator T* () const
{
return get();
}
T* operator-> () const
{
return get();
}
};
然后使用这样的东西:
#include <iostream>
#include <boost/shared_ptr.hpp>
using namespace std;
class A // simple class for example purposes
{
public:
A() : member(42) {}
int member;
};
void foo(A* a)
{
cout << "a->member=" << a->member << endl;
}
int main()
{
convertible_shared_ptr<A> ptr(new A);
foo(ptr);
cout << "ptr->member=" << ptr->member << endl;
return 0;
}
当然,我还没有在现实世界的场景中尝试过这样的事情。尝试与相应的weak_ptr
类型进行交互时可能会出现一些复杂情况。至少,可能需要更多代码来涵盖所有可能的用法。